独学大学情報学部

ただのノート。主にプログラミング。

新年明けました

新年あけましておめでとうございます。

4日程度遅延したけど気にしないことにした(
正月気分でgdgdするのもいい加減飽きたので、気分転換に日記でも。

年末

あけおめ!した直後に年末の回想ですよ奥さん。
えぇ、今年も有明開催のバーゲンセールに参加してきました。*1
以下、戦利品の一部。(意味深

f:id:Aoino:20130104010913j:plain

ざーっと眺めてみたけど、面白かったです(小並感
あとでレビューとか考察書いてみようかなーと思いつつ、一方で薄い本の内容まとめ・レビューってどうなんだろうと思ったり。*2

非常に財布と体に優しくないイベントだけど、普段会えない先輩方や話の合う人と交流出来るってのが魅力的なのでついつい。 んで、無事生還帰宅してきたわけですが数年ぶりに年越しまで起きていられませんでした......orz

元旦

友人宅にて飲み会&ゲーム

2日

友人と新春投げ売り品の買出しへ。 回線契約ついでの割引でPC買っちゃおうかなとか思ってた自分が甘かったと反省。 今更ながら、上手くできたシステムですよアレは。

3日

弟と買い物。 流行のオシャレなんてどうでもいいとか思ってたけど、流石にフクヲカイニイクフクガナイは避けたいので今風オシャレ大学生な弟様様様にご指南頂き以下割愛。

4日

なう。

抱負

今年こそ技術書含む本100冊読破!

まとめ

適当さマシマシであっと言う間に三が日終わっちゃいました。 去年は非常に色々な事があったし限界スレスレ低空飛行始まっちゃったけど、現状凄く楽しいのでこのままで上手く行ってくれればなーと。

引き続き自身の知識欲満たしつつ、色んな人と交流出来ればと思います。 今年もどうぞよろしくお願いします。


*1:お客様気分で行くと刺されますよ?

*2:何ていうか、あまり見かけないのでモヤモヤします。ダメって事は無いんだろうけども...

暗黙の型変換(Implicit Conversion)のお話

この記事はPlay or Scala Advent Calendar 2012の18日目です。
何か作ってみるとか言いながら解説記事になりました(謝
総力尽くして色々解読してますが、補足・間違い等ありましたらご指摘ください。

暗黙のパラメータ(Implicit Parameter)についても一緒にまとめようと思ったけど、長くなりそうだったので省きます...。

そもそも何なのこの機能

語弊も承知で言うならばコンパイラが勝手にやってくれる型キャストみたいな機能」 です。こりゃ確実に刺されますね、はい。
もう少しちゃんと説明すると、Scalaコンパイラは型の不一致によるエラーを検出した際に悲鳴をあげる前にスコープ内のimplicitキーワードで定義されたメソッドを用いて解決を図ります。もし、解決出来る場合はそのメソッドを自動的に挿入して実行に移ります。 既存のライブラリ直接弄ることなく拡張できちゃうすんばらしぃ機能です。

種類とか例とか

Implicit Conversionは主に「要求された型への変換」と「レシーバーの変換」の二つに分けられます。

○ 要求された型への変換
求められている型と与える型が不一致だった場合に

// もちろんエラー
scala> val num: Int = "1"
<console>:7: error: type mismatch;
 found   : java.lang.String("1")
 required: Int
       val num: Int = "1"
                      ^

// 暗黙の型変換を定義すると
scala> implicit def string2int(s: String) = s.toInt
string2int: (s: String)Int

scala> val num: Int = "1"
num: Int = 1

ってな感じで暗黙の内に変換してくれます。便利ね!!
まぁ、実際こんな変換定義したら刺される程度じゃ済まn(ry

○ レシーバーの変換
与えられた文字列にわざわざ「Lonely」を付け加えて表示するウザいメソッドlonelyString型に追加したいとすれば

// レシーバーの変換 String -> LonelyString
scala> class LonelyString(str: String) {
     |   def lonely() = println("Lonely " + str + "!!")
     | }
defined class LonelyString

scala> implicit def string2lonelyString(s: String) = new LonelyString(s)
string2lonelyString: (s: String)LonelyString

scala> "Xmas".lonely
Lonely Xmas!!

ということで、あたかもStringlonelyメソッドが存在するかの如く振る舞ってくれちゃいます。凄いね!!

制限・条件

Inplicit Conversionを発動!させるにはもちろん制限・条件があります。

  • implicitキーワードが付けられた定義のみ、暗黙の型変換に利用される
  • 単一の識別子として上記の定義がスコープ内に存在している
  • 暗黙の型変換は一回のみ適用される(型変換の型変換で整合性を取ろうとしない)
  • 明示的変換等によって元々動作する場合、暗黙の型変換は適用されない

ちなみに

上記例のレシーバーの変換について、Scala 2.10では以下の様に書くことが出来ます。

scala> implicit class LonelyString(str: String) {
     |   def lonely() = println("Lonely " + str + "!!")
     | }
defined class LonelyString

scala> "Xmas".lonely
Lonely Xmas!!

これだけでいいの!?キャー簡潔っ///
あぁ...流行に乗り遅れてる感ががが...ちゃんと仕様追いかけます(´・ω・`)

ちょっと探検

だいたいおおよそおおざっぱにお分かり頂けたと思うので、超お馴染みなScalaString型がどのようにして「すげぇRich///」になってるのか見てみましょう。*1
コップ本にもこの話はありますので読むといいかもです。

まず、Scalaコンパイラは拡張子.scalaが付いたファイル全てに以下のインポート文を暗黙のうちに追加しています。

import java.lang._
import scala._
import Predef._

ScalaStringPredefの中に

// scala/src/library/scala/Predef.scala
package scala
// ...
object Predef extends LowPriorityImplicits {
  // ...
  type String = java.lang.String
  // ...
  @inline implicit def augmentString(x: String): StringOps = 
    new StringOps(x)
  // ...
}

の様に定義されています。java.lang.Stringに対するメソッド呼び出しは暗黙のうちにaugmentStringメソッドによって StringOpsに変換されます。StringOpsは数多のメソッドを含んだクラスで、 一通り眺めるだけでお腹一杯になれます。*2

Scala 2.7の頃のString型は現在のWrappedStringへ変換されていました。WrappedStringStringOpsreversefilterメソッドの返り血が異なるくらいで、あとは似たようなものかと。*3
違いを具体的に見るならば

// Scala 2.8以降は直感的に
scala> "abc".reverse.reverse == "abc"
// => true

// WrappedStringを使うと
scala> val str = new scala.collection.immutable.WrappedString("abc")
res0: scala.collection.immutable.WrappedString = abc

scala> str.reverse.reverse == "abc"
// => false

ってな感じでおわかりいただけただろうか(震え声

ただ、Scala 2.8以降はWrappedStringへの暗黙の型変換はPredefの親クラスLowPriorityImplicits

// scala/src/library/scala/LowPriorityImplicits.scala
package scala
// ...
class LowPriorityImplicits {
  // ...
  implicit def wrapString(s: String): WrappedString =
    if (s ne null) new WrappedString(s) else null
  implicit def unwrapString(ws: WrappedString): String =
    if (ws ne null) ws.self else null
  // ...
}

と定義されていますが、コンパイラPredefLowPriorityImplicitsの継承関係より Predefに定義されている型変換を行います。*4
ってことで、普段使う分にはあまり考慮する必要がないってことですね!

まとめ

\\ Scalaすげぇ // \\ Scalaすげぇ // \\ Scalaすげぇ //


*1:Scala Standard Library 2.9.2です。

*2:実際にはStringLikeトレイトまでで大半を実装してるのでStringOpsクラスのソース自体は非常に小さいです。

*3:WrappedStringStringLike[WrappedString]StringOpsStringLike[String]をmixinしています。

*4:複数の型変換が存在する時、コンパイラはサブクラス側の型変換を選択します。

最短でつぶやくぷろぐらむ(

「今世紀最高傑作」とか「ぼくのかんがえたさいきょうの...」並に信用ならんタイトルです。 勢いとキャッチコピーは大切だと思いますぼくぁ(

準備

twitter4jとsbt使います。
Twitter Developersにアクセスして、Consumer key, Consumer secret, あとアクセストークン生成してAccess token, Access token secretをコピってきます。

手順

てけとーにディレクトリ作って、その中にbuild.sbtファイルを以下の内容で作ります。

name := "Quick Post Program"

version := "1.0"

scala := "2.9.2"

libraryDependencies += "org.twitter4j" % "twitter4j-core" % "2.2.6"

で、その後に

sbt update

とかやるとtwitter4jのjarを勝手に落としてきてパス通してくれたりします。 あとはsrc/main/scala/QuickPost.scalaってファイルにて

package main.scala

import twitter4j.conf.ConfigurationBuilder
import twitter4j.TwitterFactory

object QuickPost {
  val CONSUMER_KEY = "Consumer key"
  val CONSUMER_SECRET = "Consumer secret"
  val ACCESS_TOKEN = "Access token"
  val ACCESS_TOKEN_SECRET = "Access token secret"

  def main(args: Array[String]) {
    val builder = new ConfigurationBuilder
    builder.setOAuthConsumerKey(CONSUMER_KEY)
    builder.setOAuthConsumerSecret(CONSUMER_SECRET)
    builder.setOAuthAccessToken(ACCESS_TOKEN)
    builder.setOAuthAccessTokenSecret(ACCESS_TOKEN_SECRET)

    val twitter = new TwitterFactory(builder.build).getInstance

    twitter.updateStatus("Hello, Azusa!")
  }
}

んでもって

sbt run

で完了っと。

まとめ

自分で使うだけならこれでいいと思います。(今更感

tmuxの導入

いちいちマウス使うの面倒になってきたので導入しようかと。
タイル型WM入れても良いと思ったけど、Haskell or Luaで悩んだのでとりあえず保留。

概要

tmuxは単一画面上に複数のターミナルを起動出来るようにする便利なアプリケーションです。 "Terminal multiplexer"って書いた方が分かりやすいでそ(

導入

sudo yum install tmux

でおk。yumは適宜読み替えで。

設定

基本的な設定方法はここ読めばいけると思います。 → Manpage of TMUX
あとは"導入"ってタイトルに恥じないよう、やっておきたい初期設定をいくつか↓

  • 設定ファイル

    デフォルトでは/etc/tmux.confで、存在すれば~/.tmux.conf。
    こだわりとか深刻な事情がなければ~/.tmux.confで良いと思います。
    コメントに説明付けた設定ファイル↓ ※setはset-operationと同義。

      # Prefix keyの変更時に。デフォルトはCtrl+b
      # set -g prefix C-b
    
      # 一応自動検出されるけど、必要であれば明示的に指定。
      #setw -g utf8 on
      #set -g status-utf8 on
    
      # コピーモードのキーバインド。デフォはEmacs(
      set -g mode-keys vi
    
      # 中央のウィンドウリストは色と属性のみ変更可能です。
      # なんとなく秒も表示させたいのでintarvalは1。
      # 以下の設定で左の領域に時間、右の領域にホスト名が表示されます。
      set -g status-interval 1
      set -g status-left-length 19
      set -g status-left "%m/%d(%a) %H:%M:%S"
      set -g status-right "#H"
    

    この他、色の設定とか色の設定もあると思うけど、初期設定ならこれくらいで(

  • 基本操作

    以下を参考に。はい、手抜きです。
    時代はGNU screenからtmuxへ - Dマイナー志向
    tmuxのすすめ | catatsuyのBlog

まとめ

"tmux"って何て発音すればいいんだろう?



※12/12 右ステータスバー設定の誤字を修正("%H" → "#H")

ScalaでIntent使う時に詰まった

経緯

Scala使ってAndroidアプリの画面遷移させようとした時に ちょっと困ったのでメモ。

Scalaでクラスインスタンスを取得

JavaだとIntentをnewするとき

Intent intent = new Intent(this, CallActivity.class)

ってなるわけですが、Scalaでは

val intent = new Intent(this, CallActivity.class)

ってやると怒られます。 そもそもこの".class"ってのを普通にクラスファイル呼んでると勘違いしてました(涙目。 .classはクラスインスタンスを取得を取得するメソッドなんですね。

んで、本題のScalaではclassOfメソッドを使って

val intent = new Intent(this, classOf[CallActivity])
startActivity(intent)

で画面遷移が出来ます。




参考文献