IntelliJでScalaのシンタックスハイライト、サジェストがおかしいときに疑うこと
IntelliJ IDEAのシステムキャッシュを削除してみる
システムキャッシュの問題でシンタックスハイライトが正常に動作しない現象もまれに起こるため、まずはこれを疑ってみます。
メインメニューからFile | Invalidate Caches/Restart
を選択し、表示されるタイアログのInvalidate Caches and Restart
を選択します。
JDKのバージョンを疑ってみる
Project Structureで設定しているJDKと、JAVA_HOMEに指定しているJDKのバージョンが違う可能性があります。
例えば、明示的にJDK1.7を使いたい場合の設定は下記のようになります。
Project Structureに設定されているJDKの確認方法は、メインメニューからFile | Project Structure
を選択し(もしくはCmd+;
)、Project Settingを表示します。
ここではbrew cask
でJavaをインストールしている前提で解説します。
brew cask install java7
でインストールした、JDKは/Library/Java/JavaVirtualMachines/jdk1.7.0_72.jdk/
にインストールされています。
これに合わせて、~/.bash_profile
にJAVA_HOMEを設定します。
$ echo 'export JAVA_HOME=`/usr/libexec/java_home -v 1.7.0_72`' >> .bash_profile
.bash_profile
を読み直すと、java -version
でバージョンが変わっていることがわかります。
$ source ~/.bash_profile $ java -version java version "1.7.0_72" Java(TM) SE Runtime Environment (build 1.7.0_72-b14) Java HotSpot(TM) 64-Bit Server VM (build 24.72-b04, mixed mode)
Javaのバージョンの変更が終わったら、前述の手順のとおりに、IntelliJ IDEAのシステムキャッシュを削除し再起動すると、シンタックスハイライトが正常に動作しているはずです。
ScalaのGlobal Librariesは最新か
Project Structureに設定されているJDKの確認方法は、メインメニューからFile | Project Structure
を選択し(もしくはCmd+;
)、Platform SettingsのGlobal Librariesを表示します。
scala-sdk-2.11.6
の用に最新のものが用意されていない場合は、+
マークから追加をします。
.ivy/cacheを削除
SBTを利用している場合、~/.ivy2/cache
いかに、パッケージのキャッシュが展開されます。
これが原因となることは、今回のようなケースではあまり考えられませんが.ivy2/cache/org.scala-lang
以下のキャッシュがなんらか問題に関わっているケースもあるかもしれません。
Scalaでモナドを、なんとなくイメージするためのヒント
Scalaでモナドを説明する際には、まずリストを用いるのがイメージしやすい。
scala> List(2, 3, 5, 7, 11, 13, 17, 19).foreach(println) 2 3 5 ...
このListの値に効果を与えて、与えられたものを関数(ここではprintln
)でシーケンシャルに評価している。
次にScalaの代表的な型としてOption
があるが、これもモナドである。
Optionは値をもつ、持たないそれぞれを、Some
、None
という箱で表す。
scala> Option(10) res: Option[Int] = Some(10) scala> Option(null) res: Option[Null] = None
これに対して、リストと同じようにmap
や、filter
、foearch
などのメソッドを使うことができる。
scala> Option(10).foreach(println) 10 scala> Option(10).map(_ * 2).foreach(println) 20
また、例外処理が発生する場合に、このOptionをつくるための方法として、scala.util.Try
がある。
これによって、生成されるOption
に対して、リストと同様な処理をすることができる。
scala> import scala.util.Try import scala.util.Try // 例外が発生しないパターン scala> Try( "10".toInt ).toOption res: Option[Int] = Some(10) scala> Try( "10".toInt ).toOption.foreach(println) 10 // 例外が発生するパターン scala> Try( "fuga".toInt ).toOption res: Option[Int] = None scala> Try( "fuga".toInt ).toOption.foreach(println)
また、Optionと同様に、Futureもモナドとして扱うことができる。
Furute[Any]
に対して、やはりリストと同様に、map
やforeach
などを適用できる。
Future
の場合は、処理が行われた後に与えた関数を評価していく。
scala> import scala.concurrent._ scala> import ExecutionContext.Implicits.global scala> val f: Future[Int] = future { (1 to 100).foldLeft(0)((x: Int, y: Int) => x + y) } warning: there was one deprecation warning; re-run with -deprecation for details f: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@ca213f scala> f.foreach(println) 5050
ライブラリや自分のコードの動きを確認したいときに"sbt console"が便利
自分のプロジェクトで使っているライブラリや、書いているコードをちょっとだけテストしたい場合などに、sbt console
を利用する。
本稿では、sbt.version = 0.13.5
を想定している。
今回は、Scalaの非同期HTTP通信用ライブラリのDispatchを例に、
このライブラリをsbt console
から利用する方法をまとめた。
まずは、build.sbt
の依存ライブラリにDispatchを追加しておく。
// build.sbt name := "sbt-sample" version := "1.0" scalaVersion := "2.11.6" libraryDependencies += "net.databinder.dispatch" %% "dispatch-core" % "0.11.2"
build.sbt
を用意したら、プロジェクトのディレクトリに移動して次のコマンドを実行。
$ sbt console
すると、ライブラリの依存解決と、src以下のコンパイルが始まり、終わるとScalaREPL(対話式実行環境)が立ち上がる。
これは通常のScalaREPL(対話式シェル)と同じように見えるが、build.sbt
に記述しているライブラリ及び、プロジェクト内のパッケージを利用できる。
まずは、Dispatchのパッケージをインポートしてみる。
scala> import dispatch._, Defaults._ import dispatch._ import Defaults._
このように、インポートが実行される。 すると次のように、REPLでDispatchを利用したプログラムが実行できる。
scala> val svc = url("http://api.hostip.info/country.php") svc: dispatch.Req = Req(<function1>,Properties(NoBody)) scala> val country = Http(svc OK as.String) country: dispatch.Future[String] = scala.concurrent.impl.Promise$DefaultPromise@33304f78 scala> country.foreach(println) XX
同じように、自身で定義したObject
や、Class
も実行できるので、簡易な動作確認には役に立つ機能である。
Tuple3以上をもつListから、Tupleの値をキーにMapを作成する
たとえば、次のようなリストがあったとする。
val members = List( ("Momota", "red", 1994), ("Tamai", "yellow", 1995), ("Sasaki", "pink", 1996), ("Ariyasu", "green", 1995), ("Takagi", "purple", 1995) )
これを、Map("Momota" -> ("red", 1994), "Tamai" -> ("yellow", 1995), ...)
というMapの形にしたい。
このような場合は、Listに対してmapメソッドで処理をかけるのだが、パターンマッチを利用して次のように記述する方法がある。
val membersMap = members.map{ case (key, val0, val1) => key -> (val0, val1) }.toMap
このとき、list.map( case (a, b, c) => a -> (b ,c) )
のように()
を使うとエラーとなるので、{}
を使うようにする。
ActorSystemはインポートして使う。遅延評価する。
まず、必要なActorSystemをobjectで作っておく。 この時、ActorSystemは遅延評価(lazy val)するとよい。
// MyActorSystems.scala object MyActorSystems { lazy val someActorSystem = ActorSystem("some", config) }
ActorSystemは読み込んで使うようにする。
import MyActorSystems.someActorSystem val actor = someActorSystem.actorOf(Props[SomeActor]) actor ! SomeActorMessage( // )
Doubleにべき乗演算子をつくるには?finalクラスを拡張する方法
Scalaの暗黙の型変換については、以前にも扱った。
形式知にして使う、暗黙のimplicit - 戦略 Scala 日記
今回は、implicit class
を使って、クラスを拡張する方法を考える。
また継承が禁止されているJavaのfinalクラスを拡張して、オリジナルなメソッドをつくる例を紹介する。
scalaのDouble
では階上計算(^
)のメソッドが用意されていない。
そこで、^
を独自に定義してみる。
次のように、implicit class
でクラスを定義し、引数に拡張したいクラスをとることで、これは暗黙のクラスとして、暗黙の型変換同様にクラスを変換する。
implicit class HatDouble(d: Double)
ここで、階上計算をするためのメソッド^
を定義する。
すると、0.3^3
のように自然な計算ができるようになる。
implicit class HatDouble(d: Double) { def ^(idx: Int) = List.fill(idx)(d).fold(1.0)((d1, d2) => d1 * d2) } println(0.3^3) // => 0.027