読者です 読者をやめる 読者になる 読者になる

一歩前進

プログラミングに関する雑多なメモ

数式とUMLが記述できる静的サイト生成 Middleman + Asciidoctor の連携

Tools

PlantUMLや数式が記述できる静的サイト生成の環境が欲しいと思い調べたところ、Middleman + Asciidotor + asciidoctor-diagramで実現できたのでメモします。 (Hugoが気に入っていたのですが、現時点ではAsciiDocには対応していませんでした。)

AsciiDocはMarkdownよりも表現力が高く、リッチな文書を記述するのに向いています。 例えば以下の記事 [1]では、書籍 "Pro Git" をAsciidoctorで作成したとあります。

postd.cc

このAsciiDocですが、仕様が2つあります。 1つはオリジナルのAsciiDocで、その変換ツールPythonで作られています。 もう1つは後発のAsciidoctorで、ツールRuby製です。 両者の仕様の違いはこちら[2]。 今回は後者を使います。

インストール

環境:

  • OS X 10.10.3
  • Homebrew 0.9.5
  • Ruby 2.2.2p95
  • Git

インストールするもの:

  • JDK 1.8.0
  • Graphviz 2.38.0
  • PlantUML 8024
  • rbenv 0.4.0
  • bundle 1.10.4
  • Middleman 3.3.12
  • Asciidoctor 1.5.2
  • asciidoctor-diagram 1.3.0.preview.1
  • 他、依存パッケージ

事前準備

(1) 図の生成に必要なツール
GraphvizとPlantUMLをインストールします。 なお、PlantUMLはJava製のため、Javaをインストールしておく必要があります。

$ brew update
$ brew cask install java  # 既にJDKをインストール済みの場合は不要
$ brew install graphviz
$ brew install plantuml

(2) rbenv, bundle
gemを直接使わず、rbenvとbundleを使うので、先にそれらをインストールします。 インストール方法は以下の記事 [3]が参考になります。 ここではRuby 2.2.2を使いました。なお、Railsはここでは使いません。

qiita.com

既にrbenvとbundlerがインストール済みの場合

既にrbenvとbundlerがインストールしてある場合は、パッケージの依存関係による問題を回避するため、すべてのグローバルなgemを削除してローカルなgemで運用することをお勧めします。

グローバルなgemを削除する:

$ for i in `bundle exec gem list --no-versions | grep -v bundler`; do bundle exec gem uninstall -aIx $i; done

このとき、デフォルトのgemはアンインストールできない旨のエラーメッセージが出ますが、問題は無いので無視して先へ進みます。

Middlemanのインストール

(1) プロジェクトフォルダの作成
まず、任意の場所にプロジェクト用のフォルダを作成します。ここではmysiteというフォルダ名にします。

$ mkdir ~/mysite
$ cd ~/mysite

(2) asciidoctor-diagramリポジトリの取得 [暫定対処]
次にasciidoctor-diagramをインストールします。 gemからインストールしたいところですが、現時点でrubygemsに登録されているバージョン1.2.1は、Middleman経由で画像を生成するとParmission Deniedエラーが発生します。 バージョン1.3.0.preview.1で試したところ、エラーを回避出来ていたので、今回はこのバージョンを使います。

$ mkdir -p vendor/repo
$ cd vendor/repo
$ git clone https://github.com/asciidoctor/asciidoctor-diagram.git
$ cd asciidoctor-diagram
$ git checkout v1.3.0.preview.1

注意:
バージョンアップなどで、将来的には挙動が変わるかもしれません。 エラーの原因については、後述の「おまけ:エラーの原因」を参照してください。

(3) Gemfileの編集
Gemfileを生成するために、まずmysiteフォルダでbundle initを実行します。

$ cd ~/mysite
$ bundle init

ここでGemfileが作成されるので、次のように編集します。

# If you do not have OpenSSL installed, update
# the following line to use "http://" instead
source 'https://rubygems.org'

gem "middleman", "~>3.3.12"

# Live-reloading plugin
gem "middleman-livereload", "~> 3.1.1"

# For faster file watcher updates on Windows:
gem "wdm", "~> 0.1.0", :platforms => [:mswin, :mingw]

# Windows does not come with time zone data
gem "tzinfo-data", platforms: [:mswin, :mingw, :jruby]

# Activate support for AsciiDoc
gem "asciidoctor", "~> 1.5.2"

# Enable to embed diagrams in AsciiDoc documents.
gem 'asciidoctor-diagram', "=1.3.0.preview.1", :path => "vendor/repo/asciidoctor-diagram"

(4) gemのインストール
Gemfileの編集が終わったらgemをインストールしていきます。 --pathオプションを指定するのを忘れないで下さい。

$ bundle install --path vendor/bundle

これでインストールは完了です。

Middlemanのセットアップ

(1) サイトの生成
まずGemfileのバックアップをとり、mysiteフォルダにてmiddleman initコマンドでサイトを作ります。このときGemfileが上書きされるので、バックアップから元に戻しておきます。

$ cd ~/mysite
$ cp Gemfile Gemfile.bk
$ bundle exec middleman init .
$ mv Gemfile.bk Gemfile

(2) config.rb
次に設定ファイル(config.rb)のconfigure :build do ... endブロックの中に、次の行を追加します。 Asciidoctorでは文書の様々な属性を指定できますが、共通的に指定しておきたいものはここで設定しておきます。

config.rb:

...
configure :build do
  ...
  # Asciidoctor
  set :asciidoc_attributes, %w(source-highlighter=coderay coderay-css=style)
end

(3) MathJaxの設定
Asciidoctorで記述した数式は、HTMLに変換されるときにMathJaxのコードになります。 数式が表示されるように、MathJax.jsを読み込むようlayout.erbを編集します。 source/layouts/layout.erb を開き、<head> ... </head>ブロックの中に以下の行を追記します。

MathJaxにはいくつかの設定パラメータがありますので[4]、必要に応じて設定してください。

    <script type="text/javascript"
  src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML">
    </script>

(4) サーバ起動
それではサーバを起動してみます。

$ bundle exec middleman server

次の画面が表示されたら成功です。 f:id:succzero:20150626214914p:plain

(5) サーバ終了
サーバの終了はCtrl+Cで行います。

ページを作る

ページファイルはsourceフォルダに格納します。必要に応じて任意のサブフォルダに格納することもできます。 他のSSGのように_postフォルダに置く、といった決まりはありません。 また、ページファイルのフォーマットもMarkdownやAsciidoctorだけでなく、ERBやHaml(エクステンションを追加すればSlimも)が使えるので柔軟なWebサイトの構成が可能です。

サンプルページ

では、Asciidoctor形式のページを作ります。 sourceフォルダ直下に、次のファイルを置いてください。 ファイル中のditaaやUML図は公式ドキュメント [5]のサンプルを使いました。

sample.adoc:

:stem: latexmath
= ドキュメントタイトル

これは本文です。

== 数式を書く

インラインの数式 latexmath:[\lambda \vec{x}.M].

.ブロック形式の数式
[latexmath]
++++
\begin{align*}
e &::= c \mid x \\
  &\phantom{::}\mid \lambda x.e \mid e\;e
\end{align*}
++++



== 図を書く

.ditaaによる図
[ditaa, dia-ditaa, png]
....
                   +-------------+
                   | Asciidoctor |-------+
                   |   diagram   |       |
                   +-------------+       | PNG out
                       ^                 |
                       | ditaa in        |
                       |                 v
 +--------+   +--------+----+    /---------------\
 |        | --+ Asciidoctor +--> |               |
 |  Text  |   +-------------+    |   Beautiful   |
 |Document|   |   !magic!   |    |    Output     |
 |     {d}|   |             |    |               |
 +---+----+   +-------------+    \---------------/
     :                                   ^
     |          Lots of work             |
     +-----------------------------------+
....



.PlantUMLによるクラス図
[plantuml, dia-classes, png]
....
class BlockProcessor
class DiagramBlock
class DitaaBlock
class PlantUmlBlock

BlockProcessor <|-- DiagramBlock
DiagramBlock <|-- DitaaBlock
DiagramBlock <|-- PlantUmlBlock
....

ページをビルドする

middleman build コマンドを使います。 ただしPlantUMLやditaaなどで図を記述した場合、今のところLaTeXのように2回ビルドする必要があります。

$ bundle exec middleman build
$ bundle exec middleman build

これは1回目で画像ファイルを生成し、2回目で生成された画像ファイルを検知してbuildフォルダへ移すためです。 ビルド中にasciidoctor-diagramが生成したものを、Middlemanが検知できていないのだと思います。

結果

先ほどと同じようにmiddleman serverコマンドでサーバを起動し、ページを開きます。 sample.adocの場合はsourceフォルダの直下においているので、URLはhttp://localhost:4567/sample.htmlとなります。

sample.adocをhtmlに変換した結果は次のようになります。

f:id:succzero:20150626214935p:plain

sample.htmlが表示されない場合

sample.htmlが表示されず、buildフォルダにsample.adocが格納されている場合、 Asciidoctorとasciidoctor-diagramがインストールされていない可能性があります。 もう一度Gemfileを確認して、bundle install --path vendor/bundle を実行してください。

おまけ:エラーの原因

現行のasciidoctor-diagram-1.2.1とMiddleman 3を連携させると、画像の生成でエラーになります。 画像の出力フォルダをimagesとした場合、Middlemanはそれをサイトルート相対パスとして/imagesというパスで扱います。しかし、asciidoctor-diagram-1.2.1では、そのパスをそのまま画像の出力フォルダとして扱います。 つまり、ルートディレクトリ直下にあるimagesフォルダとなるので、書き込み権限がなくてエラーになります。

この画像出力の問題で、過去にimagesoutdirなる属性が追加されたり、いまは消えていたりと、現時点では公式な仕様がまだ確定されていません。[6]

今回は不安定なバージョンである1.3.0.preview.1を使いましたが、将来的に挙動が変わる可能性があります。 安定版である1.2.1を使いたい場合は、以下にパッチを置いておきますので、利用を検討してみてください。

https://gist.github.com/succzero/34e57c01209ed9581fd9

どちらの方法をとるにせよ自己責任でお願いします。

参考ページ

[1] テクニカルライティングの将来 ー GitHub上のAsciidocで技術書Pro Gitを協働執筆. http://postd.cc/living-the-future-of-technical-writing/

[2] Differences between Asciidoctor and AsciiDoc. http://asciidoctor.org/docs/asciidoc-asciidoctor-diffs/

[3] Rails開発環境の構築(複数バージョン共存可能)(Homebrew編). http://qiita.com/emadurandal/items/e43c4896be1df60caef0

[4] Loading and Configuring MathJax. http://docs.mathjax.org/en/latest/configuration.html

[5] Asciidoctor Diagram. http://asciidoctor.org/docs/asciidoctor-diagram/

[6] Missing documentation on imagesoutdir attribute #59. https://github.com/asciidoctor/asciidoctor-diagram/issues/59

不動点とfix演算子

プログラム言語理論 OCaml

ある関数fに対する不動点p とは、  p = f\;p なる p です。 例えば、べき乗^2を関数とみなすと、0^{2}=0, 1^{2}=1 となり、1と0はべき乗^2不動点となります [1]。

プログラム言語の教科書では \mathsf{fix} という演算子が登場します [2,3,4]。 この \mathsf{fix} と先の不動点はどう関係があるのか、フィボナッチ数の例で考えてみます。

フィボナッチ数を求める関数fibは、再帰的に定義すると次のようになります。
 fib(n) := \mathsf{if}\;n=0 \lor n=1\;\mathsf{then}\;1\;\mathsf{else}\;fib(n-1) + fib (n-2)

これをλ式で書くと
  fib = \lambda n. \mathsf{if}\;n=0 \lor n=1\;\mathsf{then}\;1\;\mathsf{else}\;\color{blue}{fib} (n-1) + \color{blue}{fib} (n-2)
となります。しかしfibは、λ抽象の本体に\color{blue}{fib}という自由変数が現れています。

自由変数が現れているので、OCamlで書くとエラーになります(ただし、型なしラムダ計算では許されます)。

# let fib = fun n -> if n==0 || n==1 then 1 else fib (n-1) + (n-2);;
Error: Unbound value fib

不動点

このままでは型付きの言語で再帰が書けません!
考え方を変えてみましょう。 次のような高階関数F_{fib}を定義します。

F_{fib} := \lambda \color{red}{f}. \lambda n. \mathsf{if}\;n=0 \lor n=1\;\mathsf{then}\;1\;\mathsf{else}\;\color{red}{f} (n-1) + \color{red}{f} (n-2)

ここで本体の式にある\color{red}{f}は、λによって束縛された変数であることに注意してください。 このF_{fib}を先ほどのfibに適用してみます。

\begin{align} F_{fib}\,fib &= (\lambda f. \lambda n. \mathsf{if}\;n=0 \lor n=1\;\mathsf{then}\;1\;\mathsf{else}\; f (n-1) + f (n-2))\;fib \\ &= \lambda n. \mathsf{if}\;n=0 \lor n=1\;\mathsf{then}\;1\;\mathsf{else}\; \color{red}{fib} (n-1) + \color{red}{fib} (n-2) \\ &= fib \end{align}

なんと、F_{fib}\,fib = fib という等式を満たすではありませんか!すなわち、fibF_{fib}不動点ということです。

しかし、fib は自由変数が含まれており、実際には定義するとエラーになりました。 ということは F_{fib}fibに適用することだって、本当はできません。 でも、高階関数F_{fib} は定義できました!

不動点コンビネータ

先のfibを定義せず、F_{fib}から不動点なるfibを求めるにはどうしたらいいんでしょうか?

不動点コンビネータは、任意の関数からその関数の不動点を対応させてくれます。 代表的な不動点コンビネータの1つに\mathbf{Y}コンビネータ [1]があり、次のように定義されます。

\mathbf{Y} = \lambda f . (\lambda x. f (xx))(\lambda x.f(xx))

Yコンビネータを使うと、

f:id:succzero:20150618125343p:plain:w400

となり、\mathbf{Y}Fn = F(\mathbf{Y}F)n であることがわかります。

F(\mathbf{Y}Fn)になるのはわかりましたが、これをどうやって計算したらいいんでしょうか? この計算には、

  • (1) 型を考えない(型なしラムダ計算)
  • (2) 名前呼び戦略で計算する

という2点を知っておく必要があります。

(1) 型なしラムダ計算

型なしラムダ計算においては、どんな2つのλ式M, N であっても、MNに適用できます[5]。*1

例として、先の \lambda x . F (\color{red}{x x})の赤字部分は、xを自分自身に適用しています。これって型を考えるとおかしいですよね。 まずFの型はF : (\mathsf{int} \to \mathsf{int}) \to  (\mathsf{int} \to \mathsf{int}) です (最初に定義したfactの型は \mathsf{int} \to \mathsf{int}でした)。 ということは、F (x x)(x x)の型は \mathsf{int} \to \mathsf{int}でなければなりません。

では、関数適用の型付け規則をみてみます。

\displaystyle \frac{e_1 : \tau_1 \to \tau_2 \;\;\; e_2 : \tau_1}{e_1\;e_2 : \tau_2}

ここで、\tau_2 の型は  \mathsf{int} \to \mathsf{int} のはずなので、

\displaystyle \frac{F : \tau_1 \to (\mathsf{int} \to \mathsf{int}) \;\;\; (xx) : \tau_1}{F\;(xx) : \mathsf{int} \to \mathsf{int}}

となります。

(x x) という式は、\tau_1型を要求されています。 これは\mathsf{int} \to \mathsf{int}でなければならないはずです。
では、(x x)xの型についてはどうでしょうか? (x x)だとわかりづらいので、(x_1\,x_2)と表記します。 いま不明な型を\alphaと表します。関数適用の型付け規則から(x_1\,x_2)の型は次のようになります。

\displaystyle \frac{x_1 : \alpha \to (\mathsf{int} \to \mathsf{int}) \;\;\; x_2 : \alpha}{(x_1\;x_2) : \mathsf{int} \to \mathsf{int}}

さて、x_1x_2の型は同じはずです。 x_1の型はいま \alpha \to (\mathsf{int} \to \mathsf{int})なので、 x_2 \alpha \to (\mathsf{int} \to \mathsf{int}) であるべきです。

\displaystyle \frac{x_1 : \color{red}{\alpha} \to (\mathsf{int} \to \mathsf{int}) \;\;\; x_2 : \color{red}{ \alpha \to (\mathsf{int} \to \mathsf{int})}}{(x_1\;x_2) : \mathsf{int} \to \mathsf{int}}

おっと、\alpha\alpha \to (\mathsf{int} \to \mathsf{int})であることを要求されてしまった!

\alpha = \alpha \to (\mathsf{int} \to \mathsf{int}) というように自身の型が再帰的に現れています。 これは再帰型と呼ばれるものだそうです。 ということは、再帰型を扱えれば型付けされたYコンビネータが扱えるということでしょうか。 試してみましょう。

$ ocaml
        OCaml version 4.01.0

#  let y = fun f -> ((fun x -> f (x x)) (fun x -> f (x x)));;
Error: This expression has type 'a -> 'b
       but an expression was expected of type 'a
       The type variable 'a occurs inside 'a -> 'b

$ ocaml -rectypes
        OCaml version 4.01.0

# let y = fun f -> ((fun x -> f (x x)) (fun x -> f (x x)));;
val y : ('a -> 'a) -> 'a = <fun>

OCaml-rectypes を使ってYコンビネータを定義できました。 しかし、OCamlは値呼び戦略の言語であるため、これを実行すると延々と再帰し続け(後述)、スタックオーバーフローになります。 なおこのオプションは、より多くの値を受け付けてしまい、読みづらい型を与えてしまう傾向があるようです [6]。

ここでは単純な型の世界で再帰関数を実現したいので、再帰型は考えないことにします。 ともかく、Yコンビネータは型なしの世界で有効なのです。

(2) 名前呼び戦略 Call by Name

型を考えないとしても、F(\mathbf{Y}Fn) すなわち、 F ( (\lambda x. F (x x) ) (\lambda x. F (x x) ) nをどのように計算すればいいでしょうか?

値呼び戦略 (Call by Value, CBV) だと延々と適用が繰り返されてしまいます。 CBVは関数適用の前に引数を先に計算して、その結果の値を関数に渡します。 試しに計算してみます。 Fの引数は(\lambda x. F (x x) ) (\lambda x. F (x x) )ですから、先にそれを計算します。

\begin{align} & F ( (\lambda x. F (x x) ) (\lambda x. F (x x) ) ) n \\ &= F ( (\lambda x. F (x x) ) (\lambda x. F (x x) ) ) n \\ &= F ( (\lambda x. F (x x) ) (\lambda x. F (x x) ) ) n \\ &= F (F ( (\lambda x. F (x x)) (\lambda x. F (x x) ) ) ) n \\ &= F (F (F ( (\lambda x. F (x x)) (\lambda x. F (x x) ) ) ) ) n \\ & \dots \end{align}

やはり延々と続いてしまいます。

では名前呼び戦略(Call by Name, CBN)はどうでしょうか? CBNでは、式の評価は名前を呼ばれるまで後回しにします。 ここで、読みやすさのためF' = (\lambda x. F (x x) ) とします。 そして、FF = \lambda \color{red}{f}.\lambda n. \mathsf{if}\;n=0 \lor n=1\;\mathsf{then}\;1\;\mathsf{else}\;\color{red}{f} (n-1) + \color{red}{f} (n-2) です。また、n=5としておきます。

ではCBNで計算してみます。

\begin{align} & F (F' F') 5 \\ &= (\lambda n. \mathsf{if}\;n=0 \lor n=1\;\mathsf{then}\;1\;\mathsf{else}\;(\color{red}{F' F'}) (n-1) + (\color{red}{F' F'}) (n-2)) 5 \\ &= \mathsf{if}\;5=0 \lor 5=1\;\mathsf{then}\;1\;\mathsf{else}\;(\color{red}{F' F'}) (5-1) + (\color{red}{F' F'}) (5-2) \end{align}

おお!5への適用ができました! 引き続き、\mathsf{if}式の中を計算していきます。 \mathsf{if}の条件は\mathsf{false}になりますから、\mathsf{else}節を計算していきます。

\begin{align} &= (\color{red}{F' F'}) (5-1) + (\color{red}{F' F'}) (5-2) \\ &= F (F' F')(5-1) + (\color{red}{F' F'}) (5-2) \\ &= (\lambda n. \mathsf{if}\;n=0 \lor n=1\;\mathsf{then}\;1\;\mathsf{else}\; (\color{red}{F' F'}) (n-1) + (\color{red}{F' F'}) (n-2) ) (5-1) + (\color{red}{F' F'}) (5-2) \\ &= (\mathsf{if}\;(5-1)=0 \lor (5-1)=1 \\ &\phantom{=(}\;\mathsf{then}\;1 \\ &\phantom{=(}\; \mathsf{else}\;(\color{red}{F' F'}) ( (5-1)-1) + (\color{red}{F' F'}) ( (5-1)-2) ) (5-1) + (\color{red}{F' F'}) (5-2) \end{align}

あとは先ほどの繰り返しです。 以上のように、Yコンビネータ再帰処理が実現できました。

fix

Yコンビネータは型のない世界では有効ですが、型付きの世界では使えません。 そこで\mathsf{fix}演算子です。 これはYと同じように不動点コンビネータとして作用します。

\mathsf{fix}は教科書によっては\mathsf{fix}\;e と書いたり、\mathsf{fix}\;f\;eと書いたりします。 先ほどのFに対して、
前者: \mathsf{fix}\;(\lambda \color{red}{f}. \lambda n. \mathsf{if}\;n=0 \lor n=1\;\mathsf{then}\;1\;\mathsf{else}\;f (n-1) + f (n-2))
後者: \mathsf{fix}\;\color{red}{f}\;(\lambda n. \mathsf{if}\;n=0 \lor n=1\;\mathsf{then}\;1\;\mathsf{else}\;f (n-1) + f (n-2))
と書きます。後者はe中のfをλで束縛するのではなく、\mathsf{fix}で束縛します。fのスコープは前者同様に、eです。 ここでは後者の定義を用います。

各規則を以下に示します。

評価規則

\frac{\displaystyle \lbrack \mathsf{fix}\;f\;e\,/\,f \rbrack\;e \hookrightarrow V}{\displaystyle \mathsf{fix}\;f\;e \hookrightarrow V}

\lbrack e'/x \rbrack e は式e中の変数xを式e'に置き換える 代入 (substitution) と呼ばれる操作を行います。 これによってF (F'F')のときのように、再帰を実現しています。

型付け規則

\displaystyle \frac{\Gamma,f:\tau \vdash e : \tau}{\Gamma \vdash \mathsf{fix}\;f\;e:\tau}

\tauは関数型を含みます。

実際に式 \mathsf{fix}\;\color{red}{f}\;(\lambda n. \mathsf{if}\;n=0 \lor n=1\;\mathsf{then}\;1\;\mathsf{else}\;f (n-1) + f (n-2))を型付けしてみます。式 (\lambda n. \mathsf{if}\;n=0 \lor n=1\;\mathsf{then}\;1\;\mathsf{else}\;f (n-1) + f (n-2))は型\mathsf{int} \to \mathsf{int}ですから、\tau = \mathsf{int} \to \mathsf{int}になります。

そしてlet recへ

\mathsf{let}\,\mathsf{rec}は、\mathsf{let}\mathsf{fix}の組み合わせで、以下のように定義できます [7]。

\mathsf{let}\,\mathsf{rec}\;x\;=\;e_1\;\mathsf{in}\;e_2\;\; \equiv\;\; \mathsf{let}\;x\;=\;\mathsf{fix}\;x\;e_1\;\mathsf{in}\;e_2

\mathsf{let}\,\mathsf{rec}のほうが使いやすいですが、\mathsf{fix}を使ったほうが計算の意味が見えてくると思います。

fixを実際に使ってみたい

\mathsf{fix} を実際に使ってみたい方(あるいは自分で実装してみたい方)は、 https://github.com/succzero/fino をどうぞ。(なお評価規則は、代入ではなく環境を使ったものになっています。) cabal build すれば使えるはずです。

OCamlではlet recを使ってしまえば、次のように\mathsf{fix}を定義できます。

# let rec fix f x = f (fix f) x;;
val fix : (('a -> 'b) -> 'a -> 'b) -> 'a -> 'b = <fun>
# let fibo = fun f -> fun n -> if n==0||n==1 then 1 else f (n-1) + f (n-2);;
val fibo : (int -> int) -> int -> int = <fun>
# fix fibo 10;;
- : int = 89

Haskellの場合はfix関数が用意されています。

Prelude> import Data.Function
Prelude Data.Function> :i
fix :: (a -> a) -> a    -- Defined in ‘Data.Function’
Prelude Data.Function> let fact = fix (\f -> \n -> if n==0||n==1 then 1 else f (n-1) + f (n-2))
Prelude Data.Function> fact 10
89

まとめ

不動点コンビネータは、任意の関数から不動点を対応付けるものです。 型なしの世界で考えられた不動点コンビネータ(Yコンビネータ)は、単純な型付きの世界では型付けできないものでした。 型付きの不動点コンビネータとして作用する\mathsf{fix}は、式あるいは型式中に再帰的に現れるfに対して、代入操作を行うことで定義できました。 そして、再帰関数を束縛できる\mathsf{let}\,\mathsf{rec}は、\mathsf{let}\mathsf{fix}によって定義付けでき、再帰関数の定義には不動点コンビネータが深く関わっていることをみてきました。

参考文献

[1] Fixed-point combinator - Wikipedia, the free encyclopedia. 2015年6月アクセス.
[2] Benjamin C. Pierce. 2002. Types and Programming Languages. MIT Press, Cambridge, MA, USA.
[3] Professor Robert Harper. 2012. Practical Foundations for Programming Languages. Cambridge University Press, New York, NY, USA.
[4] Gilles Dowek and Jean-Jacques Lvy. 2010. Introduction to the Theory of Programming Languages (1st ed.). Springer Publishing Company, Incorporated.
[5] 高橋正子 (1991). 計算論. 近代科学社.
[6] Jeremy Siek. Extensions the the Simply Typed Lambda Calculus. 2015年6月アクセス.
[7] Emmanuel Chailloux, Pascal Manoury, Bruno Pagano. Developing Applications With Objective Caml, Appendix A Cyclic Types, Option -rectypes. 2015年6月アクセス.

*1:対して、型付きλ計算では、型によって定義域・値域が一致する関数適用のみを許します。 こう言うと、型なしのλ計算は不要であるように思えます。しかし、チャーチロッサー定理など、型がなくても議論できるものは型なしで考えるほうが計算の本質を掴みやすいですし、不動点コンビネータとfixでみるように、型なしラムダ計算は型付き言語の基礎を与えています。

OCaml モジュールとシグネチャの命名規則

OCaml

モジュール名

OCamlのモジュール名は大文字から始まる必要があり、単語の区切り方は以下の2つのケースが多いようです。

  • 先頭大文字のスネークケース (例: Type_utils)
  • アッパーキャメルケース (例: TypeUtils)

前者はJane Street CoreやOcsigen等で見受けられます。後者はBatteriesやExtLib等で見受けられるスタイルです。

どちらを使うかは好みの問題なのでしょうが、特に理由がなければ

  • 公式のコーディング規約で推奨されている(ようだ)
  • Jane Street CoreやOcsigenを使った時にモジュール名の語感が合う

ということで、先頭大文字のスネークケースのスタイルを扱うのが良さそうです。

module Type_utils =
  struct
    ...
  end

シグネチャの名前

モジュールの型のようなものであるシグネチャについては、全て大文字で記述するのが慣習のようです。

module type TYPE_UTILS =
  sig
   ...
  end

ウェルズリー大学のTheory of Programming Languagesコースの資料では、 http://cs.wellesley.edu/~cs251/handouts/modules.pdf

Many OCaml programmers name signatures with all caps, but this is only a convention.

と述べられています。

コーディング規約

いくつかのコーディング規約から命名規則についてみていきます。

(1) 公式のコーディング規約

公式のコーディング規約については「アンダースコアで単語を区切る」とあります。

Caml programming guidelines

How to choose identifiers (識別子の決め方)というセクションの Separate words by underscores: (int_of_string, not intOfString) という項目です。

この「識別子(Identifiers)」が、小文字から始まる変数名や関数名のみを指しているのか、型構築子やモジュール名を含んでいるのかが気になるところです。

マニュアルをみてみると、識別子は大文字か小文字あるいはアンダースコアから始まる、と定義されています。

Lexical conventions

ということは単に「識別子」といった場合、モジュール名も該当すると考えられます。モジュールや構築子の識別子はアンダースコアで区切る、というのが推奨されているようです。(ただし、キャメルケースを使っている既存ライブラリと連携する場合は、その限りではないと書かれています。)

(2) OCaml Best Practices for Developers

Xen API (XAPI) のOCamlライブラリのプロジェクトで使われているコーディング規約です。

OCaml Best Practices for Developers - Xen

以下のように、単語の区切りはアンダースコアであり、略語が続く場合は大文字可としています。

module Parser = struct...end
module Locking_strategy = struct...end
module XML_UTF8 = struct...end

なお、シグネチャについては大文字でアンダースコア区切りとしていますが、読みやすさを妨げない事が前提となっています。

module type CAR_FACTORY = sig...end
module Fast_car_factory : CAR_FACTORY = struct...end

(3) CS3110 OCaml Style Guide

コーネル大学のData Structures and Functional Programmingのコースで配布しているコーディング規約では、構築子やモジュールの命名規則はアッパーキャメルケースとしてます。また、ファンクタについてはFnを付けています。

CS3110 OCaml Style Guide

上記資料より抜粋:

Token OCaml Naming Convention Example
Variables Symbolic or initial lower case. Use snake_case instead of studlyCaps. getItem, getItem
Constructors Initial upper case. Use StudlyCaps for multiword names. Historic exceptions are nil, true, and false. Rarely are symbolic names like :: used. Node, EmptyQueue
Types All lower case. Use underscores for multiword names. priority_queue
Signatures All upper case. Use underscores for multiword names. PRIORITY_QUEUE
Structures Initial upper case. Use embedded caps for multiword names. PriorityQueue
Functors Same as for structures, except Fn completes the name. PriorityQueueFn

先頭大文字のスネークケースというのは、他の言語ではあまり見られない慣習です。混乱を招くことが考えられる場合には、上記のような規約を導入し、特に理由が無い場合は公式のスタイルに準拠するのが良さそうです。

OCamlでPostgreSQLにアクセスする

OCaml

シンプルなPostgreSQLOCamlライブラリがないかと探したところ、Mottl氏らによるpostgresql-ocamlというライブラリがありました。

というわけで、postgresql-ocamlの導入と簡単な使い方のご紹介です。

公式ページ

Postgresql-ocaml

インストール

OPAM経由でインストールすると楽です。

opam update
opam upgrade
opam install postgresql-ocaml

インストールしたところ、ライブラリのディレクトリ(~/.opam/4.02.0/lib)にpostgresql-ocamlpostgresqlディレクトリが作成されていました。postgresql-ocaml側が空で、本体はpostgresqlディレクトリに格納されています。

ocamlfindに登録されているか確認します。

$ ocamlfind list
bigarray            (version: [distributed with Ocaml])
postgresql          (version: 2.1.0)
threads             (version: [distributed with Ocaml])
unix                (version: [distributed with Ocaml])

なお、postgresql-ocamlはbigarray, threads(とunix)を必要とします。

サンプルデータを仕込む

適当なSQLファイルを作成します。

example.sql:

-- テーブルを作成する
CREATE TABLE customers
( id INTEGER PRIMARY KEY,
  name VARCHAR(20) NOT NULL,
  address VARCHAR(60)
);

-- サンプルデータを投入する
INSERT INTO customers (id, name, address) VALUES
    (100, '山田太郎', '東京都港区'),
    (200, '佐藤一郎', '東京都千代田区');

SQLファイルをロードします。

$ psql -U user1 example -f example.sql

ここではデータベース、テーブル、所有者を以下のようにしています。

  • データベース名: example, 所有者: user1
  • テーブル名: customers, 所有者: user1

PostgreSQLのセットアップやコマンドの使い方はこちらを参照: MacでPostgreSQL - 一歩前進

サンプルコード

前半は通常のクエリ発行で、後半はprepared statementを使用しています。

#use "topfind";;
#thread;;
#require "postgresql";;

open Printf
open Postgresql

(* DB名、ユーザ名、パスワードを指定してconnectionクラスのインスタンスを作成する *)
let conn = new connection ~dbname:"example" ~host:"localhost" ~user:"user1" ~password:"user1" ()
(* SQL文;$1, $2, ... でプレースホルダを指定できる *)
let query = "SELECT id, name, address FROM customers WHERE id = $1"

(* 取得した結果を表示する関数 *)
let show res =
  for tuple = 0 to res#ntuples - 1 do
    for field = 0 to res#nfields - 1 do
      printf "%s, " (res#getvalue tuple field)
    done;
    print_newline ()
  done

(* 受け取った文字列sをパラメータとしてクエリを発行し、結果を出力する *)
let run s = show @@ conn#exec ~expect:[Tuples_ok] ~params:[| s |] query;;
(* @@ はHaskellの$と同じく、( ) を省略するためのもの
 * ~ はラベル付き引数
 * ~expectは、結果がTuples_ok(データが返ってきた場合)以外であれば例外を出すという指定
 * ~paramsでプレースホルダにバインドするパラメータを、配列で指定
 *)

run "100";;
(* => 100, 山田太郎, 東京都港区, *)
run "200";;
(* => 200, 佐藤一郎, 東京都千代田区, *)
run "300";;
(* => (表示されない) *)


(* test1 という識別名でprepared statementを作る *)
assert ((conn#prepare "test1" query)#status = Command_ok);;

let prepared_run s name =
  show @@ conn#exec_prepared ~expect:[Tuples_ok] ~params:[|s|] name
;;

prepared_run "100" "test1";;
(* => 100, 山田太郎, 東京都港区, *)

prepared_run "200" "test1";;
(* 200, 佐藤一郎, 東京都千代田区, *)

prepared_run "300" "test1";;
(* => (表示されない) *)

MacでPostgreSQL

Mac PostgreSQL

MacPorts経由でMacPostgreSQLをインストールしたときのメモです。ここでは、サーバ運用は考慮せず、シングルユーザでの利用を想定しています。

通常ユーザのプロンプトを%、postgresユーザのプロンプトをpostgres$で示します。

インストール

% sudo port install postgresql93 +universal
% sudo port install postgresql93-server

ユーザ環境の設定

postgresユーザの設定

PostgreSQLをインストールするとpostgresというユーザが自動的に作成されます。

postgresユーザを有効化せずに、su - postgres -c コマンドによって間接的にpostgresユーザとしてコマンドを実行する方法もあるのですが、頻繁に管理作業を行う場合はコマンドが煩雑になるため、postgresユーザを有効にしておきます。

パスワードの設定

postgresユーザにパスワードを設定して、アカウントを有効にします。

% sudo passwd postgres
Changing password for postgres.
New password: パスワードを入力
Retype new password: パスワードを再度入力
環境変数を設定する

.profileを作成して、各種環境変数を設定します。

なお、postgresユーザのホームディレクトリは/opt/local/var/db/postgresql93です。

% cd /opt/local/var/db/postgresql93
% sudo vi .profile

以下のような内容でパスおよびPGLIB, PGDATAを設定します。

export POSTGRES_HOME=/opt/local/lib/postgresql93
export PATH=${POSTGRES_HOME}/bin:${PATH}
export PGLIB=${POSTGRES_HOME}
export PGDATA=/opt/local/var/db/postgresql93/defaultdb

保存したら所有権を変更しておきます。

% sudo chown postgres:postgres .profile

一般ユーザの設定

次に、普段使用しているユーザの設定を行います。

パスを通す

MacPortsPostgreSQLパッケージは、postgresql93やpostgresql84等、バージョンごとにパッケージが分かれています。そのため、コマンドの格納先が/opt/local/postgresql93/binとなっていますが、port selectコマンドを使うことで/opt/local/binにコマンドへのシンボリックリンクを貼ることが出来ます。

postgresqlのバージョンをpostgresql93にする:

% sudo port select --set postgresql postgresql93
Selecting 'postgresql93' for 'postgresql' succeeded. 'postgresql93' is now active.

確認する:

% port select --list postgresql
    none
    postgresql93 (active)

元に戻す場合:

% sudo port select --set postgresql none
Selecting 'none' for 'postgresql' succeeded. 'none' is now active.

設定の再読込み:

port select --setを使ったらターミナルを再起動するか、.zshrc.bashrcを読み込みます。

% source ~/.zshrc

これでpg_ctlpsqlコマンドにパスが通りました。

% which pg_ctl
/opt/local/bin/pg_ctl
環境変数の設定

環境変数PGDATA.zshrc.bashrcに設定します(コマンドへのパスは通っているので、POSTGRES_HOME等は設定しません)。 後述するデータベース・クラスタの名前はdefaultdbにしてします。

export PGDATA=/opt/local/var/db/postgresql93/defaultdb

ターミナルを再起動するか、設定を再ロードします。

% source ~/.zshrc

データベース・クラスタの作成

データベース・クラスタはディスク上のデータベース格納領域であり、1つのサーバインスタンスで管理されるデータベースの集合とのこと。Oracleでいうデータベース(≠データファイル)に相当するものでしょうか。

(参考:データベースクラスタの作成

(1) ディレクトリの作成

defaultdbという名前でディレクトリを作成し、パーミッションpostgresにします。 既に${PGDATA}にディレクトリパス/opt/local/var/db/postgresql93/defaultdbを設定しているので、これを利用します。

% sudo mkdir -p ${PGDATA}
% sudo chown postgres:postgres ${PGDATA}

(2) initdbの実行

次に、先ほど作成したdefaultdbディレクトリを指定してinitdbコマンドを実行します。initdbはpostgresユーザで実行する必要あります。su - postgresのようにハイフンを指定することで、現ユーザの環境を引き継がないようにして余計なトラブルを回避します。

日本語を扱えるようにするため、initdbのオプションに--encoding=UTF-8 --locale=ja_JP.UTF-8を指定しています。他のエンコーディングを使いたい場合はそれを指定してください。ただし、encodingとlocaleが異なるとデータを破壊する原因になるようです。(参考:ロケール(国際化と地域化) — Let's Postgres)

なお、postgresユーザ環境に環境変数PGDATAを設定しているため、-D /opt/local/var/db/postgresql93/defaultdbのようにディレクトリへのパスを指定する必要はありません。

% su - postgres
(postgresユーザのパスワード入力)
postgres$ initdb --encoding=UTF-8 --locale=ja_JP.UTF-8
The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.

The database cluster will be initialized with locale "ja_JP.UTF-8".
The default database encoding has accordingly been set to "UTF8".
initdb: could not find suitable text search configuration for locale "ja_JP.UTF-8"
The default text search configuration will be set to "simple".
...

WARNING: enabling "trust" authentication for local connections
You can change this by editing pg_hba.conf or using the option -A, or
--auth-local and --auth-host, the next time you run initdb.

Success. You can now start the database server using:

    postgres -D /opt/local/var/db/postgresql93/defaultdb
or
    pg_ctl -D /opt/local/var/db/postgresql93/defaultdb -l logfile start

WARNING:の部分では、デフォルトではTrust認証を使っているので注意ってことらしい。ここではシングルユーザ(個人)で使うだけなのでデフォルトのままにしておきます。

(参考:https://www.postgresql.jp/document/9.3/html/auth-methods.html

起動と停止

起動:

postgres$ pg_ctl start
もしくは
% sudo su - postgres -c "pg_ctl -D ${PGDATA} start"

停止:

postgres$ pg_ctl stop
もしくは
% sudo su - postgres -c "pg_ctl -D ${PGDATA} start"

(参考:pg_ctlコマンド https://www.postgresql.jp/document/9.3/html/app-pg-ctl.html

サポートスクリプトを使う場合

MacPortsでは、/opt/local/etc/LaunchDaemons/org.macports.postgresql93-serverディレクトリに起動・停止のためのサポートスクリプトがインストールされていました。

これを使って.zshrcあたりにエイリアスを設定しておくと、postgres以外のユーザから起動・停止がしやすくなります。

alias pg_start='sudo /opt/local/etc/LaunchDaemons/org.macports.postgresql93-server/postgresql93-server.wrapper start'
alias pg_stop='sudo /opt/local/etc/LaunchDaemons/org.macports.postgresql93-server/postgresql93-server.wrapper stop'

データベースに対する一般ユーザの作成

現在のdefaultdbには管理ユーザpostgresしかいないため、一般ユーザを作成しておきます。(ここでのユーザはOSのユーザではなく、PostgreSQLdefaultdbクラスタに登録されたユーザのことを指します)

ここで作成する一般ユーザの名前を普段使用しているOSのユーザ名と同じにしておくと、psql等のコマンドを実行する際に-U 接続ユーザ名の指定を省略できるようになります。 しかし、CやJavaのプログラムからPostgreSQLサーバに接続して使用することを想定するため、異なるユーザ名を指定します。

# サーバ起動
postgres$ pg_ctl start
# 対話環境の起動
postgres$ psql
psql (9.3.5)
Type "help" for help.

postgres=#

# 別のユーザが対話環境を起動する場合:
% psql -U postgres ← 接続ユーザを指定する

ユーザ一覧の確認:

\duコマンドでユーザの一覧を確認します。

postgres=# \du
                             List of roles
 Role name |                   Attributes                   | Member of
-----------+------------------------------------------------+-----------
 postgres  | Superuser, Create role, Create DB, Replication | {}

現在はpostgresユーザしかいません。

ユーザの作成:

別のターミナルを立ち上げ、createuserコマンドでuser1というユーザを追加します。

% createuser -U postgres -P user1
Enter password for new role: (パスワードを入力)
Enter it again:(パスワードを入力)

スーパーユーザ権限を与えるなどのオプションは--helpオプションで確認できます。 再度\duコマンドで確認するとuser1ユーザが作成されています。

postgres=# \du
                             List of roles
 Role name |                   Attributes                   | Member of
-----------+------------------------------------------------+-----------
 postgres  | Superuser, Create role, Create DB, Replication | {}
 user1     |                                                | {}

データベースの作成

先ほど作成したuser1ユーザを所有者にして、exampleというデータベースを作成します。

% createdb -U postgres --owner=user1 example

psqlから\lコマンドでデータベースの一覧を確認すると、exampleデータベースが表示されます。

postgres=# \l
                                  List of databases
   Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges
-----------+----------+----------+-------------+-------------+-----------------------
 example   | postgres | UTF8     | ja_JP.UTF-8 | ja_JP.UTF-8 |
 postgres  | postgres | UTF8     | ja_JP.UTF-8 | ja_JP.UTF-8 |
 template0 | postgres | UTF8     | ja_JP.UTF-8 | ja_JP.UTF-8 | =c/postgres          +
           |          |          |             |             | postgres=CTc/postgres
 template1 | postgres | UTF8     | ja_JP.UTF-8 | ja_JP.UTF-8 | =c/postgres          +
           |          |          |             |             | postgres=CTc/postgres
(4 rows)

テーブルの作成

まず、\c データベース名 ユーザ名で作成先のデータベースに切り替えます。テーブルの所有者をuser1で作成するため、ユーザ名にuser1を指定しています。

postgres=# \c example user1
You are now connected to database "example" as user "user1".

ここからは通常のSQLコマンドを実行していくだけです。

example=# CREATE TABLE customers
example-# ( id INTEGER PRIMARY KEY,
example(# name VARCHAR(20) NOT NULL,
example(# address VARCHAR(20)); ← セミコロンで文を閉じる
CREATE TABLE

SQLファイルを直接実行する場合

# 作成するテーブルの所有者:user1
# 作成先のデータベース:example
% psql -U user1 example -f setup.sql 

さらなる設定

そのほかの設定はここでは割愛しますが、postgresql.confpg_hba.conf等の各種設定ファイルは/opt/local/var/db/postgresql93/defaultdb直下にあります。

また、参考になるリンクをご紹介しておきます。

コマンドを簡略化するため、postgresアカウントを有効にしましたが、ひと通りの管理作業が終わったらpostgresアカウントを無効(初期状態)に戻すとセキュリティ的に安心です。初期状態に戻すにはpasswdコマンドで空のパスワードを設定します。

コマンドまとめ

コマンド 説明
pg_ctl start サーバ起動
pg_ctl stop サーバ停止
createuser -P ユーザ名 ユーザ追加
dropuser ユーザ名 ユーザ削除
createdb --owner=所有者名 データベース名 データベース追加
dropdb データベース名 データベース削除
psql -U 接続ユーザ名 データベース名 -f SQLファイル SQLファイルを処理する
  • pg_ctlコマンドはpostgresユーザから実行
  • その他のコマンドはPostgreSQLユーザ以外のユーザから操作する場合は、-U 接続ユーザ名オプションを付加

(上記以外のコマンド: https://www.postgresql.jp/document/9.3/html/reference-client.html)

psqlメタコマンド:

コマンド 説明
\l データベースを列挙する
\du データベースのユーザ(ロール)を一覧表示する
\z テーブル、ビュー、シーケンスの一覧を表示する
\c データベース名 ユーザ名 現在のデータベースを切り替える
\cd ディレクトリ 作業ディレクトリを変更する
\h SQLコマンド SQLの構文に関するヘルプを表示する
\o ファイル名 クエリの結果をファイルに出力する
\r コンソールバッファをクリアする
\q 対話環境を終了する

(上記以外のコマンド : https://www.postgresql.jp/document/9.3/html/app-psql.html)

MacTeX 2014

Mac TeX

TeX環境を入れ直したのでメモ。

なんだかんだでhomebrewからMacPortsに戻ってきました。

MacPortsにはtexのパッケージが用意されています。しかし、MacPortsからインストールするとTeXのパッケージ管理ツールTeX Live Manager(tlmgr)での管理が出来ないのと、パスがTeXの共通的な/usr/texbinではなく/opt/localなパスになって、他の人とのTeXに関するスクリプトの共有が難しくなります。というわけで、ここはやはりMacTeX (TeX Live)を使います。

方針:TeX Live Managerで管理されないものはMacPortsで管理する

MacTex 2014にはps => pdf 変換に使われるghostscriptがバンドルされていますが、これはTeX Live Managerの管理対象外なので、MacPortsで管理することにします。

1. インストールするもの

パッケージ名 内容 備考
ghostscript ps => pdf変換等々に使われる MacPortsからインストールする
ImageMagick TeXに画像を埋め込むときに、png, jpg等々の画像からepsに変換するためによく使う MacPortsからインストールする
MacTeX 2014 デファクトスタンダードTeXディストリビューションであるTeX Liveと、Mac用のGUIアプリ、ghostscriptをバンドルしたもの ここでは必要最小限のGUIアプリを導入するため、TeX Live 2014のみインストールします
TeX Live Utility パッケージ管理ツール TeX Live Manager (tlmgr)のフロントエンド 個別にインストールします

MacTeX 2014には、

  • TeX Live 2014
  • ghostscript
  • GUI アプリケーション

が同梱されています。MacTeXに同梱されたGUIアプリは今回扱いませんが、紹介だけしておきます。

MacTeXに同梱されたGUIアプリ(今回は割愛):

  • TeXShop: TeXのエディタ。これ使うよりvim使いましょう。
  • TeXworks: TeXの統合環境、補完機能とかある。それよりvim使おう。
  • BibDesk: 文献管理ツール。これ使うならJabRefかMendeleyがオススメ。
  • LaTeXiT: 数式エディタ。パワポに数式を貼り付けるのに便利。
  • TeX Live Utility: TeXのパッケージ管理ツール。個別にインストールするので、MacTeX に同梱されているものは無視。
  • Excalibur: スペルチェッカ。誤字脱字は恥ずかしいのであったほうがいいかも。

2. 前提環境

  • OS X 10.9.4
  • MacPorts
    • homebrew等、他のパッケージ管理ツールを使っている場合は適宜読み替えて下さい
    • パッケージ管理ツールを導入していない場合は、MacTeX 2014インストール時に、インストール項目にGhostscriptを含めてください

3. インストール

3.1 ghostscript

ghostscriptは、ページ記述言語であるPostScriptとPDFのインタプリタであり、これらのデータを入力として、ラスタ画像(ビットマップ画像)に変換し、印刷やビューアでの表示、あるいはPostScript <-> PDF間の変換に使われます。

CUPS対応のghostscriptを導入するなら、+cupsオプションをつけておきましょう。

$ sudo port install ghostscript +universal +cups + x11

3.2 ImageMagick

ImageMagickは様々なフォーマットの画像に対するフォーマット変換やリサイズ、回転、色調整等々の各種操作を扱うソフトウェアスイートです。

以下のオプションを指定してインストールします。 大量の依存パッケージがインストールされますが、細かいコトは気にしないようにしましょう。問題があるようなら、オプションを変えてパッケージを再インストールすればいいのです。

$ sudo port install ImageMagick +graphviz +jbig +jpeg2 +pango +rsvg +universal +wmf +x11

オプションが気になる方へ:

ImageMagickパッケージは依存関係のある厄介なオプションが多く、パッケージのオプションを注意深く検討しているporterにとっては要注意パッケージです。

特に、ImageMagickパッケージの+graphvizオプションを有効にしたときに依存するgraphvizパッケージは、オプションとそれに依存するパッケージが多いので、気になる方は事前にgraphvizを導入しておいたほうがいいでしょう。

3.3 MacTeX 2014

以下から、MacTeX.pkgをダウンロードします。

https://tug.org/mactex/

ダウンロードしたpkgを実行し、TeX Live 2014のみをインストールするようにします。

f:id:succzero:20140713104236p:plain

インストールが完了したら、環境がTeX Live 2014になっていることを確認します。

Appleマーク→「システム環境設定」→「TeX Distribution」を開き、TeXLive-2014が選択されていることを確認します。

f:id:succzero:20140713115608p:plain

4. パッケージ管理

まず、GUIツールを入れておくフォルダを作ります。

$ mkdir -p /Applications/TeX

4.1 Tex Live Utilityのインストール

以下から、最新のTeX Live Utilityをダウンロードします。ダウンロード一覧の中にはBETA版が混在していますが、避けたほうがいいです。

https://code.google.com/p/mactlmgr/

ここでは、TeX Live Utility.app-1.17.tar.gzをダウンロードしました。このファイルを展開して、出てきた.appファイルを/Application/TeXに移動してください。

4.2 パッケージの最新化

TeX Live Utilityを起動すると、自動的にパッケージの一覧を取得しにいくので、しばらく待ちます。

メニューの「作業」→「すべてのパッケージを更新」を選びます。

f:id:succzero:20140713105907p:plain

4.3 pmetapost, pxdvi の導入

4.3.1 pmetapost, pxdviとは

pmetapostはMetaPostを日本語に対応させたものです。

MetaPostは、図形描画のための一種のプログラミング言語であり、そのインタプリタでもあります(ドナルド・クヌース先生のMetafontという言語に基いていて、構文的に類似性があるそうです)。 重要なのは直接EPS(Encapsulated PostScript)を生成できるところで、これによってベクトルデータのみを含むようなepsが扱えるようになります。pngやjpgといった画像からepsに変換することも出来ますが、ビットマップデータを含む形になってしまい、画像がややぼやけてしまう問題があります。綺麗な図形を扱うならmetapostというわけです。pmetapostを使うことで、日本語文字の入った図形を描画できます。

pxdviは、dviビューアであるxdviの日本語化版です。(Mac環境でこれを使うことはあまりないので、こっちはどうでもいい)

4.3.2 tlptexliveリポジトリによるパッケージの導入

これらpmetapost, pxdviを扱っているリポジトリがtlptexliveであり、TeX Live 2014 版のURLは以下になります。

http://www.tug.org/~preining/tlptexlive/

(参考: http://www.preining.info/blog/2014/05/tex-live-2014%E3%81%AEtlptexlive/

※以前はptex, uptexも上記のリポジトリから導入していましたが、現在ではTeX Liveに取り込まれたようです。

このURLを、Tex Live UtilityのURLに貼り付けると、

http://www.tug.org/~preining/tlptexlive/リポジトリにはTeX Live 2013がありますが、ここに導入されているものは TeX Live 2014です。続行するにはリポジトリを切り替えなくてはなりません。

f:id:succzero:20140713201328p:plain

というエラーが出て先に進めません。(2014年7月現在)

ここでは、コマンドラインから直接リポジトリを追加してパッケージを導入していきます。

$ sudo tlmgr repository add http://www.tug.org/~preining/tlptexlive/ tlptexlive
tlmgr: added repository with tag tlptexlive: http://www.tug.org/~preining/tlptexlive/

$ sudo tlmgr pinning add tlptexlive '*'
tlmgr: package repositories:
    main = http://mirror.ctan.org/systems/texlive/tlnet
    tlptexlive = http://www.tug.org/~preining/tlptexlive/
tlmgr: new pinning data for tlptexlive: *

$ sudo tlmgr install pxdvi pmetapost
tlmgr: package repositories:
    main = http://mirror.ctan.org/systems/texlive/tlnet
    tlptexlive = http://www.tug.org/~preining/tlptexlive/
...(中略)...
done running mtxrun --generate.

これで、pxdvi, pmetapostが導入できました。

5. 日本語フォントの設定

PDFはフォントを埋め込むことが出来ます。逆にフォントを埋め込まない場合、(特に印刷所での印刷で)文字化けを起こす可能性があります。 学会等ではフォント埋込みを要求しているところが多く、フォント埋め込みがなされていない場合は投稿時にエラー、なんてところもあるようです。

TeX Live 2014はデフォルトで埋込みがなされない(noEmbed)設定になっています。というわけで、ここでは、日本語フォントを埋め込む設定を行っていきます。

MacTeXに関するページで、よくヒラギノフォントの設定が書かれていますが、これをやってしまうと、気づかないうちにヒラギノフォントを埋め込んだPDFを外部に公開してしまうのでオススメしません(ご自身の利用ケースではライセンス的に問題無いことが明確であれば別です)。

かといって、ライセンスフリーIPA, IPAexフォントは太字が無いため、単にIPA, IPAexフォントにすればいいというものでもありません。 そのため、明朝の太字、ゴシックの太字等々、パターンに応じたフォントの用意とそのフォントマップの設定をする必要があります。(太字をゴシックで代用する方法で問題なければ、IPAexフォントでいいと思います)

ここでは、以下のthomas氏のページを参考に、基本的な5種類のフォントについて具体的な設定を行っていきます。ディレクトリやファイル名等は若干変えていきます。

参考:http://www.fugenji.org/~thomas/texlive-guide/font_setup.html
(フォントに関する問題を知っておくためにも、一読されることをお勧めします。ここでは単にMacでのインストール作業について述べます。)

No. フォントの種類 採用するフォント
(1) 明朝 IPAex 明朝
(2) ゴシック IPAex ゴシック
(3) ボールド明朝 MogaMincho Bold
(4) ボールドゴシック MigMix 2P Bold
(5) 丸ゴシック MigMix 1M Regular

5.1 FontBookの設定

フォントは、ユーザディレクトリ側ではなくシステム側にインストールします。 まず/Applications/Font Book.appを起動します。(Launchpadの場合、「その他」の中にあります)

f:id:succzero:20140713211213p:plain

次にメニューの「Font Book」→「環境設定」を開き、デフォルトのインストール場所を「コンピュータ」に変更しておきます。

f:id:succzero:20140713211342p:plain

5.2 (1) 明朝、(2)ゴシック

基本となる明朝・ゴシック体フォントは、IPAexフォントを使います。

IPAフォントとIPAexフォントの違いは、IPAフォントが固定幅フォント(IPA 明朝等)と可変幅フォント(IPA P明朝等)で別れていたのに対し、IPAexフォントでは和文文字が固定幅、欧文文字が変動幅となっており、日本語文書の慣例に沿っている点が特徴的です。

IPAexフォントはTex Live 2014に同梱されておりそれをインストールすればいいのですが、ここでは新たにダウンロードしてインストールします。 ダウンロードは以下から行います。

http://ipafont.ipa.go.jp/ipaexfont/download.html

2書体パックとなっているものをダウンロードすると手っ取り早いです。

2書体パック(IPAex明朝(Ver.002.01)、IPAexゴシック(Ver.002.01)) IPAexfont00201.zip(9.31 MB)

ファイルを展開すると、「ipaexg.ttf」と「ipaexm.ttf」が出てくるので、それぞれインストールします。 このとき、ユーザ側に同じフォントがインストールされていないことを確認します。もしインストールされていた場合は、先にそのフォントをアンインストールしておきます。

f:id:succzero:20140713212247p:plain

次に、texliveフォルダにIPAexフォントのリンクを貼ります。

# texliveのフォントフォルダに移動する
$ cd /usr/local/texlive/texmf-local/fonts
# IPAexフォントを格納するフォルダを作成する
$ sudo mkdir -p truetype/public/ipaex
# インストールしておいたIPAexフォントのリンクを貼る
$ sudo ln -fs /Library/Fonts/ipa*.ttf ./

5.3 (3) ボールド明朝

明朝のボールドはMogaMinchoを使用します。 現状では、フリーなフォントとしてはこれが唯一の選択肢のようです。

以下のページにMogaMinchoを含む「ゴシック&明朝 MoboGothic / MogaGothic / MogaMincho TTCパック」がありますので、それをダウンロードします。

http://yozvox.web.fc2.com/82A882B782B782DF8374834883938367.html

ここでは、MoboMoga-001.02.12b.7zをダウンロードしました。 これを展開し、「mogamb.ttc」をダブルクリックすると、複数のフォントが表示されます。

f:id:succzero:20140714002256p:plain

これらをひと通りインストールします。

次にフォントのシンボリックリンクを作成します。

$ cd /usr/local/texlive/texmf-local/fonts/truetype/public
$ sudo mkdir moga
$ cd moga
$ sudo ln -fs /Library/Fonts/mogamb.ttc .

5.4 (4) ボールドゴシック、(5)丸ゴシック

ゴシック体のボールドにはMigMix 2P、丸ゴシックとしてMigMix 1Mを使います。

以下のページから、MigMix 2PとMigMix 1Mのファイルをそれぞれダウンロードします。

http://mix-mplus-ipa.sourceforge.jp/migmix/

(今回は、migmix-2p-20130617.zip, migmix-1m-20130617.zipをダウンロードしました。)

それぞれのzipファイルを展開して、

  • MigMix 2P: migmix-2p-bold.ttf
  • MigMix 1M: migmix-1m-regular.ttf

をそれぞれインストールします。 先と同様に、シンボリックリンクを作成します。

$ cd /usr/local/texlive/texmf-local/fonts/truetype/public/
$ sudo mkdir migmix
$ cd migmix
$ sudo ln -fs /Library/Fonts/migmix-*.ttf ./

5.5 フォントマップの設定

(1) マップファイルの配置

マップファイルを格納するフォルダを作成します。

$ cd /usr/local/texlive/texmf-local/fonts/
$ sudo mkdir -p map/dvipdfmx/jfontmaps/allfree

次に、以下のファイルをptex-allfree.mapというファイル名で保存し、/usr/local/texlive/texmf-local/fonts/map/dvipdfmx/jfontmaps/allfreeに格納します。 ※ 以下のファイルはthomas氏のmapファイルを若干修正したものです。

platex-allfree.map:

rml           UniJIS-UTF16-H                  ipaexm.ttf
rmlv          UniJIS-UTF16-V                  ipaexm.ttf
rml           Identity-H                      ipaexm.ttf
rmlv          Identity-V                      ipaexm.ttf
rml           H                               ipaexm.ttf
rmlv          V                               ipaexm.ttf
unijmin-h     UniJIS-UTF16-H                  ipaexm.ttf
unijmin-v     UniJIS-UTF16-V                  ipaexm.ttf
cidmin-h      Identity-H                      ipaexm.ttf/AJ16
cidmin-v      Identity-V                      ipaexm.ttf/AJ16

gbm           UniJIS-UTF16-H                  ipaexg.ttf
gbmv          UniJIS-UTF16-V                  ipaexg.ttf
gbm           Identity-H                      ipaexg.ttf
gbmv          Identity-V                      ipaexg.ttf
gbm           H                               ipaexg.ttf
gbmv          V                               ipaexg.ttf
unijgoth-h    UniJIS-UTF16-H                  ipaexg.ttf
unijgoth-v    UniJIS-UTF16-V                  ipaexg.ttf
cidgoth-h     Identity-H                      ipaexg.ttf/AJ16
cidgoth-v     Identity-V                      ipaexg.ttf/AJ16

otf-ujmr-h    UniJIS-UTF16-H                  ipaexm.ttf
otf-ujmr-v    UniJIS-UTF16-V                  ipaexm.ttf
otf-cjmr-h    Identity-H                      ipaexm.ttf/AJ16
otf-cjmr-v    Identity-V                      ipaexm.ttf/AJ16
hminr-h       H                               ipaexm.ttf
hminr-v       V                               ipaexm.ttf

otf-ujgr-h    UniJIS-UTF16-H                  ipaexg.ttf
otf-ujgr-v    UniJIS-UTF16-V                  ipaexg.ttf
otf-cjgr-h    Identity-H                      ipaexg.ttf/AJ16
otf-cjgr-v    Identity-V                      ipaexg.ttf/AJ16
hgothr-h      H                               ipaexg.ttf
hgothr-v      V                               ipaexg.ttf

otf-ujmb-h    UniJIS-UTF16-H                  :1:mogamb.ttc
otf-ujmb-v    UniJIS-UTF16-V                  :1:mogamb.ttc
otf-cjmb-h    Identity-H                      :1:mogamb.ttc/AJ16
otf-cjmb-v    Identity-V                      :1:mogamb.ttc/AJ16
hminb-h       H                               :1:mogamb.ttc
hminb-v       V                               :1:mogamb.ttc

otf-cjgb-h    Identity-H                      migmix-2p-bold.ttf/AJ16
otf-cjgb-v    Identity-V                      migmix-2p-bold.ttf/AJ16
otf-ujgb-h    UniJIS-UTF16-H                  migmix-2p-bold.ttf
otf-ujgb-v    UniJIS-UTF16-V                  migmix-2p-bold.ttf
hgothb-h      H                               migmix-2p-bold.ttf
hgothb-v      V                               migmix-2p-bold.ttf

otf-ujmgr-h   UniJIS-UTF16-H                  migmix-1m-regular.ttf
otf-ujmgr-v   UniJIS-UTF16-V                  migmix-1m-regular.ttf
otf-cjmgr-h   Identity-H                      migmix-1m-regular.ttf/AJ16
otf-cjmgr-v   Identity-V                      migmix-1m-regular.ttf/AJ16
hmgothr-h     H                               migmix-1m-regular.ttf
hmgothr-v     V                               migmix-1m-regular.ttf

注意点として、上記のフォントファイル名(migmix-2pp-bold.ttf等)の箇所は、大文字小文字が区別されるため、実際のファイル名と合わせて下さい

余談ですが、上記のmapファイルのファイル名には、先頭にplatex-と付けています。これをつけておかないと、マップの反映をする際に次のようなエラーが発生します。

$ kanji-config-updmap allfree
NOT EXIST ptex-allfree.map

スクリプトをみると、mapファイルの先頭にptex-を決め打ちで付けていました(3行目)。

sub SetupMapFile {
  my $rep = shift;
  my $MAPFILE = "ptex-$rep.map";
  if (check_mapfile($MAPFILE)) {
    print "Setting up ... $MAPFILE\n";
    system("$updmap --quiet --nomkmap --nohash -setoption kanjiEmbed $rep");
    if ($opt_jis) {
      system("$updmap --quiet --nomkmap --nohash -setoption kanjiVariant -04");
    } else {
      system("$updmap --quiet --nomkmap --nohash -setoption kanjiVariant \"\"");
    }
    system("$updmap");
  } else {
    print "NOT EXIST $MAPFILE\n";
    exit 1;
  }
}
(2) ls-Rデータベースの更新

ひと通りのフォントのセットアップが終わったら、mktexlsrコマンドでls-Rデータベースを更新します。 このls-Rは、/usr/local/texlive/texmf-local以下のテキストファイルの検索を高速化するために用いられるものです。

$ sudo mktexlsr
mktexlsr: Updating /usr/local/texlive/2014/texmf-config/ls-R...
mktexlsr: Updating /usr/local/texlive/2014/texmf-dist/ls-R...
mktexlsr: Updating /usr/local/texlive/2014/texmf-var/ls-R...
mktexlsr: Updating /usr/local/texlive/texmf-local/ls-R...
mktexlsr: Done.
(3) マップファイルの適用
$ kanji-config-updmap allfree

上記の場合、ユーザ環境に個別に設定が適用されます。システム全体に適応した場合は、sudo kanji-config-updmap-sysコマンドを使用してください。

5.6 ヒラギノフォントを埋め込む場合

以下のコマンドをコピペして実行するだけで設定できます。

sudo mkdir -p /usr/local/texlive/texmf-local/fonts/opentype/hiragino/
cd /usr/local/texlive/texmf-local/fonts/opentype/hiragino/
sudo ln -fs "/Library/Fonts/ヒラギノ明朝 Pro W3.otf" ./HiraMinPro-W3.otf 
sudo ln -fs "/Library/Fonts/ヒラギノ明朝 Pro W6.otf" ./HiraMinPro-W6.otf
sudo ln -fs "/Library/Fonts/ヒラギノ丸ゴ Pro W4.otf" ./HiraMaruPro-W4.otf
sudo ln -fs "/Library/Fonts/ヒラギノ角ゴ Pro W3.otf" ./HiraKakuPro-W3.otf
sudo ln -fs "/Library/Fonts/ヒラギノ角ゴ Pro W6.otf" ./HiraKakuPro-W6.otf
sudo ln -fs "/Library/Fonts/ヒラギノ角ゴ Std W8.otf" ./HiraKakuStd-W8.otf
sudo ln -fs "/System/Library/Fonts/ヒラギノ明朝 ProN W3.otf" ./HiraMinProN-W3.otf
sudo ln -fs "/System/Library/Fonts/ヒラギノ明朝 ProN W6.otf" ./HiraMinProN-W6.otf
sudo ln -fs "/Library/Fonts/ヒラギノ丸ゴ ProN W4.otf" ./HiraMaruProN-W4.otf
sudo ln -fs "/System/Library/Fonts/ヒラギノ角ゴ ProN W3.otf" ./HiraKakuProN-W3.otf
sudo ln -fs "/System/Library/Fonts/ヒラギノ角ゴ ProN W6.otf" ./HiraKakuProN-W6.otf
sudo ln -fs "/Library/Fonts/ヒラギノ角ゴ StdN W8.otf" ./HiraKakuStdN-W8.otf
sudo texconfig-sys rehash

実際にヒラギノフォントのマップファイルを適用するには、以下を実行します。

$ kanji-config-updmap hiragino

5.7 確認

テキトーなファイルを作って、allfree版とhiragino版それぞれの結果を確認してみます。

せっかくuplatexがTeX Liveにバンドルされているので、uplatexを使いましょう。{jsarticle}の前に、uplatexを指定します。

sample.pdf:

\documentclass[uplatex]{jsarticle}
\usepackage[expert, deluxe]{otf}
\usepackage{amsthm}

\begin{document}
\section{漢字とひらがなとカタカナ}
\subsection{漢字とひらがなとカタカナ}
\subsubsection{漢字とひらがなとカタカナ}
これは通常のテキストで、明朝で表示されます.


{\bf ボールド明朝}{\gt ゴシック}{\bf \textgt{ボールドゴシック}}、そして{\mgfamily 丸ゴシック}の書体が使い分けられます.

\noindent {\bf 集合}(set)とは、ものの集まりのことである.

\noindent {\gt 集合}(set)とは、ものの集まりのことである.

\noindent {\bf \textgt{集合}}(set)とは、ものの集まりのことである.

\end{document}

Makefileはちゃちゃっとこんな感じで。(スペース4つはタブに読み替えてください)

Makefile:

LATEX=uplatex
PDFLATEX=pdflatex
DVIPDFM=dvipdfmx
TARGET=sample.pdf

.PHONY: all clean

all: $(TARGET)

clean:
    /bin/rm -f *.dvi *.out *.nav *.snm *.vrb *.toc *.aux *.log *.pdf

%.pdf: %.dvi
    dvipdfmx $<

%.dvi: %.tex
    uplatex -interaction=batchmode $<

結果をみてみましょう。

allfree版:

f:id:succzero:20140715111841p:plain

hiragino版:

f:id:succzero:20140715112128p:plain

集合(set)とは〜、の下りのところは、上からボールド明朝、ゴシック、ボールドゴシックです。

allfree版で示したMogaMincho Boldはやや太さが足りない気がします。やはりヒラギノフォントは優秀です。フォントについて考えだすときりがないので、(クオリティについては)商用の出版物でない限り気にしないことにします。

5.8 フォントマップ切り替え

  • デフォルトに戻す
kanji-config-updmap noEmbed
  • allfreeなフォント埋込みにする
kanji-config-updmap allfree
kanji-config-updmap hiragino

システム全体に適用する場合はkanji-config-updmap-sysを使います。また、以前はupdmap-setup-kanjiというコマンド名でしたが、現在ではkanji-config-updmapに変わっています。

Vim + Vim-LaTeX

Vimtexプラグインは、Vim-LaTeXが有名らしいです。

インストール

NeoBundleを使っている場合、.vimrcに以下の行を加えてvimを起動すれば勝手にインストールされます。

NeoBundle 'git://git.code.sf.net/p/vim-latex/vim-latex'
.vimrcの設定と使い方

.vimrcの設定はこちらをそのままコピペします。

使い方は、以下のページが詳しいです。

http://oku.edu.mie-u.ac.jp/~okumura/texwiki/?Vim-LaTeX#v4639f7b

さらなる詳細は、vimから:help latex-suiteで出てきます。

特に使用頻度の高そうな機能を紹介すると、以下の操作でコンパイルと表示が出来ます。いずれもノーマルモード時にて。

  • \ll(バックスラッシュの後に素早くエルを2回)
  • \lv
    • pdfの表示

特に、Preview.appを使っている場合、pdfを表示したまま\llで再コンパイルすると、その結果がそのまま反映されます。

\llすら面倒だ、という方にはOMakeを使用することをオススメします。 OMakeでtexコンパイルするのはこのあたりが参考になります。

http://d.hatena.ne.jp/hayamiz/20081208/1228727272

texのファイルが変更されたことを監視して勝手にコンパイルしてくれるので、

texファイルを更新・保存」
 ↓
(OMakeがコンパイル
 ↓
「Preview.appが勝手に再読み込み」

という擬似リアルタイムプレビューの完成です。

それでは新しいTeX環境で素敵な執筆ライフを!

参考にさせていただいたページ

TeX Wiki, 「Vim-LaTeX
http://oku.edu.mie-u.ac.jp/~okumura/texwiki/?Vim-LaTeX

Norbert Preining, 「TeX Live 2014のtlptexlive」
http://www.preining.info/blog/2014/05/tex-live-2014%E3%81%AEtlptexlive/

Tamotsu Thomas UEDA, 「日本語フォントのセットアップ」
http://www.fugenji.org/~thomas/texlive-guide/font_setup.html

hayamiz, 「OMake つかって LaTeX コンパイルしたら簡単すぎて身長が5cm伸びた」
http://d.hatena.ne.jp/hayamiz/20081208/1228727272

MacにF#をビルド&インストールする

MacでF# 3.1をビルドしたときのメモ。

0. 前提環境

1. 事前準備

(1) autoconf, automake, libtool

MacPortsやHomebrewあたりで、autoconf, automake, libtoolを用意しておきます。\ 今回使ったバージョンは以下のとおりです。

  • autoconf @2.69_2 (active)
  • automake @1.14.1_2 (active)
  • libtool @2.4.2_3+universal (active)
(2) stow

自前でビルドしたパッケージを管理するためにstowを用意しておきます。 MacPortsの場合:

$ sudo port selfupdate
$ sudo port install stow
(3) ディレクトリの準備

ソースコードを格納するディレクトリ(src)と、ビルドしたパッケージを格納するディレクトリ(stow)を作成します。

$ sudo mkdir -p /usr/local/{src, stow}

※ビルド時にいちいちsudoするのが面倒な場合はsrcディレクトリをchownしておいてください

2. Mono

(1) ビルド

F#を実行するための環境として、monoランタイムをビルドします。

$ cd /usr/local/src
$ sudo git clone https://github.com/mono/mono
$ cd mono
$ sudo ./autogen.sh --prefix=/usr/local/stow/mono --enable-nls=no --disable-bcl-opt
$ sudo make get-monolite-latest
$ sudo make
$ sudo make install

--disable-bcl-optは、BCL(基本クラスライブラリ)を最適化なしでコンパイルしてデバッグを有効にするものです。パフォーマンスが気になるなら外しておいたほうがよいでしょう。

またmake get-monolite-latestをしておかないと、以下のようなエラーが出ます。

File `DoesNotExist' referenced in TOC but it doesn't exist.
(2) インストール(リンク)

前述の作業で/usr/local/stow/monoにmonoランタイムがインストールされたので、stowを使ってこれを/usr/local/{bin,lib,share,...}ディレクトリにリンクさせます。

$ cd /usr/local/stow
$ sudo stow mono

/usr/local/binにパスが通っていれば、これでmonoランタイムが使えるようになります。

$ mono -V
Mono JIT compiler version 3.4.1 (master/adcc774 2014年 5月30日 金曜日 23時19分09秒 JST)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
    TLS:           normal
    SIGSEGV:       altstack
    Notification:  kqueue
    Architecture:  amd64
    Disabled:      none
    Misc:          softdebug
    LLVM:          supported, not enabled.
    GC:            sgen

3. F#

(1) ビルド
$ sudo git clone https://github.com/fsharp/fsharp
$ sudo ./autogen.sh --prefix=/usr/local/stow/fsharp
$ sudo make
$ sudo make install
(2) インストール(リンク)
$ cd /usr/local/stow
$ sudo stow fsharp
(3) ライブラリパスの設定

DYLD_FALLBACK_LIBRARY_PATHを.bashrcあたりに設定しておきます。
設定値はご自身の環境に合わせて変更してください。 (特にここでは、/usr/local/lib, /usr/libが必須になります)

$ export DYLD_FALLBACK_LIBRARY_PATH=${HOME}/lib:/usr/local/lib:/opt/local/lib:/lib:/usr/lib:${DYLD_FALLBACK_LIBRARY_PATH}$

ここでライブラリのパスが正しく設定されていないと、以下のようなエラーが出ます。

Failed to install ctrl-c handler - Ctrl-C handling will not be available. Error was:
Exception has been thrown by the target of an invocation.

上記の場合、実行中のF#コードをインタラクティブから中断する事はできません。(止まらない計算を中断できなくなります)

使ってみる

インタラクティブを使う

WindowsではfsiコマンドでF# Interactiveを立ち上げますが、Macではfsharpiコマンドを使います。

fsharpiはただのラッパーシェルで、実際はmono fsi.exeを実行しています。 monoは、exe形式のMSILコードを実行時にコンパイルします。

$ fsharpi
F# Interactive for F# 3.1 (Open Source Edition)
Freely distributed under the Apache 2.0 Open Source License

For help type #help;;
> 1+1;;
val it : int = 2
> printfn "Hello, World";;
Hello, World
val it : unit = ()

インタラクティブの終了は、Ctrl+ZかCtrl+Dです。

実行中のF#コードを中断したい場合は、Ctrl-Cを実行します。

> while true do printfn "Hello, F Sharp" done;;
Hello, F Sharp
Hello, F Sharp
Hello, F Sharp
Hello, F Sharp
Hello, F Sharp
....
(Ctrl + C を押す)
- Interrupt
コンパイラを使う

適当なコードを作成します。 fact.fs:

let rec fact n =
    if n=0 then 1
    else n * fact (n-1)

[<EntryPoint>]
let main (args:string[]) =
    printfn "%d" (fact (int args.[0]))
    0

※上記ではint32の値で計算しているため、nの値が大きいと正しく計算されません。

F#のソースコードコンパイルするときはfsharpcコマンドを使います。

$ fsharpc fact.fs

すると、fact.exeファイルが作成されますが、exe形式のためmonoコマンドを経由して実行します。

$ mono fact.exe 5
120

おまけ. fsharp-vim

VimでF#のシンタックスハイライトをさせたかったので、NeoBundleでfsharp-vimを入れました。

NeoBundle 'kongo2002/fsharp-vim'

fsharp-vim
https://github.com/kongo2002/fsharp-vim