kmizuの日記

プログラミングや形式言語に関係のあることを書いたり書かなかったり。

Scala Nativeを動かしてみた(1)

Scala Nativeはscalaのコードを(LLVMのIRを経由して)ネイティブコードにコンパイルするAOTコンパイラ(Ahead Of Time Compiler)です。その存在については、少し前にサイトができていたことで一部で話題になっていましたが、Scala Days 2016 NYCにて正式に公開されました。現在はPre-Release段階ですが、既にサンプルコードを試せるようになっていたので、環境を構築してみました(on Mac OS)。

$ git clone git@github.com:scala-native/scala-native.git --recursive

git submoduleとしてscala/scalaを持っているので、--recursiveを付けるのを忘れないようにしましょう。

  • llvm(clang)とbdw-gcをインストールする
$ brew install --with-clang llvm
...
$ brew install bdw-gc
$ sbt
> project rtlib
> publishLocal
> project nscplugin
> publishLocal
  • デモプロジェクトに移動(sbtを起動したまま)
> project demoNative
  • 実行(gc.hがないといったエラーが出るはず)
> run
  • bdw-gcにパスを通す
nativeClangOptions := Seq("-I/usr/local/Cellar/bdw-gc/7.4.2/include", "-L/usr/local/Cellar/bdw-gc/7.4.2/lib")

この、nativeClangOptionsというsettingKeyは、ここで定義されていて、要はclangに渡すオプションを格納するためのものです。インクルードパスとライブラリパスの両方を渡してやります。なお、ここでは、明示的にbdw-gcをインストールしたディレクトリにパスを通しましたが、うまくやればそもそもここでつまづく事はない…かもしれません。うまくいかない場合はこの辺をいじればなんとかなるということでもあります。

  • 再度実行
> run

なにやら色々warningが出ますが、それはともかく、赤枠で囲った部分が表示されればひとまず成功です。 f:id:kmizushima:20160512221647p:plain

Scala Nativeを試してみたいけど、うまく行っていない人が居るようだったので、とりあえず走り書き程度ですが、参考になればと思います。気が向いたら、サンプルプログラムをちょっといじってなんかやってみたいと思います。

Kotlin用不変コレクションライブラリ kollection 0.2リリース

  • リストベースの集合であるKListSet
  • リストベースのマップであるKListMap
  • 遅延評価を提供するKLazy

のサポートを追加しました。また、必要になった時点で、KListにもメソッドを随時継ぎ足していってます。詳細についてはREADMEを参照ください。

github.com

Kotlinでメソッド定義にrunを使う意義

Kotlinにはrun というメソッドがstdlibにあります。これ、定義をみると、

@kotlin.internal.InlineOnly
public inline fun <R> run(block: () -> R): R = block()

引数で渡された0引数ラムダ式(とKotlinの用語法に従っておく)をそのまま呼び出すだけというものになっています(もう一バージョンあるのですが、そっちについては割愛)。本来の意味での用途かはわからないですが、これが役に立つケースとして、メソッド定義でreturnを書かなくても済むというものがあります。

たとえば、引数を取り、それぞれを出力した後、二つの値を足したものを返すメソッドprintAndAddは、通常は以下のように書く必要があります。

fun printAndAdd(x: Int, y: Int): Int {
  println(x)
  println(y)
  return x + y
}

さて、このreturn必須というのが、(式ベースの言語から来ると)地味に嫌なわけですが、この制限をrunを使って回避することができます。以下のように書き換えるだけです。

fun printAndAdd(x: Int, y: Int): Int = run {
  println(x)
  println(y)
  x + y
}

runにその場で生成したラムダ式を渡して実行するという形になりますが、ラムダ式の返り値の型をKotlin処理系が推論してくれるため、書く必要がなくなっています。

ところで、メソッド呼び出しのたびにラムダ式が生成されるというと実行コストが気になる人がいるかもしれませんが、心配ご無用。runにインラインで渡された無名関数はそのままインライン展開されるため、オーバーヘッドはほぼゼロです。

試しに、次のコードをコンパイルしてみます:

fun add(x: Int, y: Int): Int = run {
  x + y
}

javapした結果:

Compiled from "P.kt"
public final class PKt {
  public static final int add(int, int);
    Code:
       0: nop
       1: iload_0
       2: iload_1
       3: iadd
       4: ireturn
}

nopが入ってしまっているのが多少残念ですが、さすがにこのレベルで無駄なコードはJITコンパイラが消去してくれることを期待できますし、万が一消去してくれなかったとしても、メソッド一つにつきnop命令一つ分のオーバーヘッドはほぼ無視できます。

ただ、性能面での問題点はないものの、Kotlinの標準的な慣習に沿っていないという点はやや微妙かもしれません。まあ、その辺は統一してrunを使っていれば問題は少ないのではないかとも思いますが。

stripMarginの歴史

ScalaのString(正確にはStringOps)にはstripMarginというメソッドがあります。これは、主に複数行文字列に使われる機能で、たとえば、

"""|class Hello {
   |  
   |}""".stripMargin

のようにすると、

res0: String =
class Hello {

}

という文字列が得られ、行頭のスペースを除きたい場合に非常に便利な機能です。この機能、どうやらGroovyにもあるらしく、名前もまんまstripMarginです。さて、これ、GroovyがScalaのそれにインスパイアされたのか、それとも逆なのか調べていたところ、Groovyの過去のIssueにstripMargin()を追加するというものがあり、

[GROOVY-3349] Add stripMargin() to multi-line strings - ASF JIRA

どうやらScalaのstripMargin()が先のようです。他には、npmのstripmarginがありますが、これは、

A helper for strip string's margin like scala

なので、元がScalaということのようです。Kotlinにはメソッド名を微妙に変えた trimMargin

kotlinlang.org

というメソッドがありますが、登場年代からしても、おそらくScalaの影響を受けたものでしょう。他にも類似メソッドがあるかもしれませんが、とりあえずこんなところで。

Kotlin用不変コレクションライブラリ kollection 0.1リリース

ちょっと前から少しずつ作っていたのですが、最低限の機能はそろったので公開してみることにしました。Kotlinの標準ライブラリのコレクションは読み取り専用ビューは提供してくれるものの、不変コレクションがないのが不満だったので作ってみようというのが動機です。

github.com

ドキュメントは未整備ですが、現時点で

を使うことができます。

たとえばこんな感じです:

KList(1, 2, 3, 4, 5).foldLeft(0){a, e -> a + e} //15
KList(1, 2, 3) zip KList(4, 5, 6) // KList(Pair(1, 4), Pair(2, 5), Pair(3, 6))

詳細についてはテストコード を読んでみてください。

今後も継続的に扱える不変コレクションの種類を充実させていきます。

Scala 2.12.0-M4とJava 8 Streamで遊んでみる

Scala 2.12.0-M4はまだ正式リリースはされていませんが、既に各種バイナリはpublishされており、sbtに次のようにscalaVersionを書いてあげればふつうに使うことができます。

scalaVersion := "2.12.0-M4"

さて、Scala 2.12の一つの目玉がSAM Type(Single Abstract Method Type)変換です。これは、Java 8で可能になった、無名関数を抽象メソッドを一つだけ持つインタフェース型に変換できるようにするものです。また、同時に、invokedynamicを使った実装も入ったことによって、これまで、無名関数一つに付きクラスファイル一つが生成されていた状況が大幅に改善されることになります(M3と同じ部分も多くあると思いますが、せっかくfeature completeになったのであえて書いてみることにしました)。

さて、SAM Typeへの変換ができるようになったので、せっかくなのでJava 8のStream APIを使ってみることにしました。コードは次のような感じです:

gist.github.com

試してみて気づいたのですが、SAM Type変換に関して、これが仕様なのかM4時点での制限かはわかりませんが、Stream[String]に対してmapメソッドを呼び出す際に、型パラメータStringを明示しないとコンパイルエラーになってしまいました(エラーメッセージをみると、どうもワイルドカード絡みの推論がうまく行っていない気がします)。この辺の罠があるので、現時点でScalaからJava 8 Stream APIを使うのは面倒ですが、推論がうまく行くようになれば実用的に使うことができるのではないかと思います。

gitbook-plugin-regexplaceを利用して、ブロックレベル要素でMarkdownを囲む

GitBookは、色々な電子フォーマットで出力するドキュメントのためのツールです。

github.com

GitBookは紹介記事がたくさんあると思うので、説明は割愛しますが、このツール、主な記述言語としてMarkdownを採用しています。Markdown自体は色々な独自拡張がありますが、基本的にはプレーンなMarkdown+Github-Flavored-Markdownでサポートされている記法が使えるようです。

Markdownはシンプルな記法ですが、それだけでは表現力が不足することがあり、そういう場合、HTMLを書けということになっています。これで全て解決すればいいのですが、残念ながらそうはいきません。MarkdownにHTMLの断片を埋め込むのは簡単ですが、その逆はかなり厳しい制限がついています。

Daring Fireball: Markdown Syntax Documentation

に記述があるのですが、HTMLのブロックレベル要素内にはMarkdownを埋め込むことができないのです。この制限を緩和した、PHP Markdown Extraという拡張がありますが、これはGitBook内では使うことができません。

PHP Markdown Extra

この制限が問題になる場合はいくつかあるのですが、たとえば、

<div id="scala_code1" style="...">
 ```scala
 val foo = 1
 ```
</div>

のように、シンタックスハイライトされたコードをブロックレベル要素で囲み、それに対して特定のスタイルを適用したい、あるいはidを振りたいといった場合に困ることになります。

Markdownの処理過程に介入できない場合、基本的にはお手上げなのですが、幸いにもGitBookにはプラグイン機構があり、HTMLなどに変換する途中に別の処理を挟み込むことができます。

今回は、gitbook-plugin-regexplaceを使って問題を解決しました。このプラグイン、名前のごとく、Markdownの中で、特定の正規表現にマッチした文字列を別の文字列に置き換えるという機能を提供してくれます。

これを利用して、book.jsonに次のような記述を追加します:

{
  "plugins": [
    "regexplace"
  ],
  "pluginsConfig": {
    "regexplace": {
      "substitutes": [
        {"pattern": "<!-- begin div id=\"(.*)\" style=\"(.*)\" -->", "flags": "g", "substitute": "<div id=\"$1\" style=\"$2\">"},
        {"pattern": "<!-- end div -->", "flags": "g", "substitute": "</div>"}
      ]
    }
  }
}

その上で、本文に

<!-- begin div id="div1" style="display:none" -->
Markdown
<!-- end div -->

のように記述すると、HTMLに変換される際に、

<div id="div1" style="display:none">
Markdown
</div>

のように置き換えられるようになります。正直な話、正規表現による文字列マッチングで何でもかんでもやるのは好みではありませんが、木構造ベースの変換モデルを用意してくれていない(はず)以上、このような方法をとるしかないのでした。類似の機能を提供するプラグインとして、gitbook-plugin-sectionxというのがあるのですが、他のプラグインが使っているスタイルと衝突があったのかどうか、意図通りの結果が得られませんでした。