- もう 2 月か、早いな。
- 最近は焼きそばをよく作っている。
つい忘れるので書いておこう。
$ sudo port install python27
実際は他の何かを入れた際に依存関係で入っていたようなのでやっていない。
$ pip install virtualenv $ virtualenv -p (which python2.7) ~/py27 # (which python2.7) は fish の書き方
config.fish
に以下を追加する。
set -x PATH $HOME/py27/bin $PATH
see also
最近また自炊するようになった。これまでと少しスタンスを変えて、食材を一度にたくさん買わないようにした。当日か、最大でも翌日には使い切るくらいのものしか買わない。内容量によっては残ることもあるけれどあまり気にしない。
幸い自宅からスーパーまでそんなに離れていないので、実際に計測してみたら往復しても大して時間はかからないことがわかったし、むしろ運動になってちょうどよいのだと考えるように切り替えた。
今までは、ある程度まとめて買う方が効率的だろうと考えていたけれども、自炊スキルがあまり高くないこともあって、たくさん買おうとすると「用途のイメージがクリアではないけれども購入する」という部分の占める割合が大きくなっていたと思う。
そして「外食するかもしれないし、自炊するかもしれない」という曖昧な状態だと、自炊を選択しない場面も出てくるので使いきれないうちに傷んでしまったりして、しょんぼりした気持ちになったりする。
一方、今日はこれを作ろう、だからアレとアレを買おう、と明確に決まっている状態であれば売り場でも迷わないし、買って帰って作って食べる、とスムーズな進行が可能になる。言われてみれば当たり前だけどさ。
ただ、もう少し短時間で済ませられるようになりたいというのはある。
これ、すごくよかった。このつくりで 100 円で買えるというのはちょっと信じられない。自宅と会社の両方に設置しても 216 円!
買いだめしておいた方がよいだろうかと考えてしまうレベル。置く場所がないから難しいけれど。
会社で他の人にも使ってもらっているツールについて、うまく動かないようだという連絡をもらったので、エラーの内容を確認するためのバッチファイルを用意した。
@echo off rem 実行する.bat のディレクトリに移動 cd /d %~dp0 set log_file="log.txt" echo ---------- >> %log_file% rem %var:~i,j% で var の i 文字目から j 文字目までを抜き出す rem i は 0 始まり echo %date% %time:~0,8% >> %log_file% set host=%COMPUTERNAME% echo host: %host% >> %log_file% set user=%USERNAME% echo user: %user% >> %log_file% echo ----- >> %log_file% rem ログを取りたいアプリケーションを実行 rem something.exe >> %log_file%
コマンドプロンプトはテキストのコピペがやりにくかったり、色々とフレンドリーではないよね。
PowerShell は起動が遅いし実行権限の設定を変更しないとスクリプトを実行できなかったり、管理者用という感じの印象。
(last update: 2018/01/22)
しばらく書いてなかったな。
先週末にノート PC の OS をインストールしなおしたのでセットアップしてた。
少し前に OS を high Sierra にアップデートしてみたら、Haskell の管理ツール stack
が動かなくなったみたいで、これもよいきっかけと思いクリーンインストールしなおすことにした。
数年前から各種設定ファイルは ~/dotfiles
にまとめて Github で管理しているので、ここから引っ張ってきてちょこちょこと作業すればいいのだけれど、今回は少し変更したいところもあったので設定ファイルを作り直すことにした。
変更したかったのは
init.el
を分割する$GOPATH
を $HOME/go
ではなく $HOME
にするなどなど。
これまでは Cask を使っていた。~/.emacs.d/Cask
というファイルに使いたいパッケージを記入しておくと $ cask install
とコマンド実行するだけで全部インストールしてくれるもの。
これはこれで便利だったけれど、use-package
というパッケージを使えば、elisp のみでパッケージのインストールとその設定をまとめて記述することができて、外部コマンドを導入する必要もなくすっきりするので、変更してみたくなった。
use-package
のいいところrequire
したパッケージが入っていなかった場合でも init.el
の読み込み自体はエラーにならない。:ensure t
と書いておくとそのパッケージをインストールしてくれるこんな感じ。
;; https://github.com/benma/visual-regexp.el (use-package visual-regexp :ensure t :bind (("M-%" . vr/query-replace)) )
分割をやめた方の話も一応。
grep の代替となる高速検索ツール、ag とか名前は聞いたことがあったけれど使っていなかったので今後は活用してみたい。そもそも grep すらあまり使っていないので何かと効率悪いことをしていると思われる。
anything と組み合わせて便利な感じになったりするんだと思う。多分。もしかしたら helm じゃないとだめなのかな。
何ならもう一回、rubikitch 先生の有料メルマガを購読して質問してみるのがいいかもしれない。
ripgrep 入れようとしたらスムーズにいかなかくて yak shaving 感あったと tweet したら作者の方からバイナリあるよ、とリプライいただいてびっくりした。
素直にダウンロードして /usr/local/bin
に置いておいた。まだ使いこなせていないけれどせっかくだから使いたい。
You can download pre-compiled binaries for Windows, Mac or Linux: https://t.co/mFtDwKBVBG
— Andrew Gallant (@burntsushi5) 2018 年 1 月 18 日
Go の TOML ライブラリの作者として認識していた。すごい人はいろいろすごい。
昨年使い始めてから、もう二度と zsh や bash には戻れないと思わせる、とても便利なシェル fish。
今回は、使いたい関数は config.fish
に直接書けばいいかなと思い、プラグインマネージャー fisherman は入れなかった。実際、ヒストリ検索と ghq 管理下のリポジトリに cd
するやつの 2 つがあれば満足かなと。
って思っていたのだけれど、z
という最近 cd
したディレクトリを列挙してくれるツールが快適そうに思えてきて、やっぱり fisherman 入れようかなと少し揺れているところ。
一回使ってみようかしらん。
設定ファイル init.el
の内容を見直しつつ、分割して、書き直していった。一つ一つ調べながらやっていたら、結局一週間かかった。
Github にある既存のリポジトリをいずれ差し替えたいのだけれど、Git の操作に疎いのでひとまず bitbucket に置いた。(公開設定がプライベートになっていたので修正した)
README.md
の更新もだいたい落ち着いたのでようやく一息つけるわ。
ソースファイル .ml
をコンパイルするとオブジェクトファイル .cmo
や .cmx
.o
と同時にインターフェイスファイル .cmi
が生成される。
この .cmi
について調べてみた。理解してしまえば何ということはないのだけれど、少し時間がかかった。
.mli
をコンパイルすると .cmi
が生成される。.mli
がない場合は .ml
から .cmi
が生成される。では .mli
とは何だろう。
ではモジュールとは、シグネチャとは何だろう。
詳細な解説は以下の記事、資料を読むとよさそう。
ただ、一度に全部を理解しようとするのはかなり困難だったので、ひとまずは「関連する処理やデータなどのまとまり」くらいの理解でよいと思う。Python や Go でいうパッケージと同じようなものだと考えればよいだろう。
OCaml では一つのファイルを一つのモジュールとするそう。前回書いた、階乗を求める処理でもモジュールとして扱っていた。
fact.ml
は Fact
モジュールとなる。
(* fact.ml *) let rec fact n = if n = 0 then 1 else n * fact (n - 1)
利用する側からは open
で読み込む。
(* main.ml *) open Fact let () = print_int (fact 10); print_newline()
もしくは、モジュール名.関数
の形でドット .
をつけてモジュール内の関数を利用する。
(* main.ml *) let () = print_int (Fact.fact 10); print_newline()
Python で as
で別名をつけて import
するのと同じように
import numpy as np
以下の書き方で別名をつけて open
することができる。
module F = Fact let () = print_int (F.fact 10); print_newline()
open
というキーワードは使わない。F
の部分は大文字で始める必要あり。モジュールについては他の言語でも似たような仕組みはあるので、何となくではあるけれどわかった。次はシグネチャである。
OCaml におけるシグネチャは、モジュールの中身に対するアクセスの可否を制御する仕組みで、個々の関数には private とか public とかつけずに別途まとめて管理できるようになっている。
今まで触ったことのある言語(Python, Go, JavaScript あたり)ではこれに該当するものはなかったと思われ、新鮮に感じた。言語によっては、関数の仮引数や戻り値の型、アクセス修飾子などのことを指してシグネチャと呼ぶ場合があるみたいだけれど。
Python だと名前の頭にアンダースコア _
や __
をつけることで private 扱いになり、Go だと名前の頭文字が大文字なら外部からアクセス可能で小文字だとアクセス不可、という仕様になっている。
で、OCaml の場合。
Fact
モジュールを少し拡張して試してみる。階乗 n!
のバリエーションとして多重階乗というものがあるらしい。二重階乗 n!!
であれば一つ飛ばしで積をとる。
5!! = 5 * 3 * 1 10!! = 10 * 8 * 6 * 4 * 2
この多重階乗を求める関数 multifact
を書いてみた。
(* fact.ml *) let rec fact n = if n = 0 then 1 else n * fact (n - 1) let rec multifact x n = match n with | 0 -> 1 | 1 -> 1 | _ -> if x > n then n else n * multifact x (n - x) let doublefact = multifact 2
モジュールを利用する側のコード。
(* main.ml *) open Fact let () = print_int (fact 10); print_newline (); print_int (multifact 2 10); print_newline (); print_int (doublefact 10); print_newline (); ;;
実行結果はこうなる。
# コンパイルして $ ocamlc -o fact10 fact.ml main.ml # 実行する $ ./fact10 3628800 # fact 10 3840 # multifact 2 10 3840 # doublefact 10
*.mli
に書く次に Fact
モジュールのシグネチャを fact.mli
に書く。公開するものだけを書き、シグネチャに書かれていないものは外部からアクセスできなくなる。
試しに multifact
は非公開としてみる。
(* fact.mli *) val fact : int -> int val doublefact : int -> int
このシグネチャの書式はコンパイラに -i
オプションをつけて当該ファイルを渡すと確認できる。-i
オプションのみの場合は実際のコンパイルはしない(.cmo
ファイルは生成されない)。
$ ocamlc -i fact.ml val fact : int -> int val multifact : int -> int -> int val doublefact : int -> int
*.mli
にリダイレクトして、公開したくないものを削除すればよい。
$ ocamlc -i fact.ml > fact.mli
ファイル *.mli
が存在する場合は、*.ml
よりも先にコンパイルしないとエラーになる。
$ ocamlc -c fact.ml File "fact.ml", line 1: Error: Could not find the .cmi file for interface fact.mli.
fact.mli
をコンパイルして、
$ ocamlc -c fact.mli # fact.cmi が生成される
fact.ml
をコンパイルして、
$ ocamlc -c fact.ml # fact.cmo が生成される
main.ml
をコンパイルしようとすると、エラー!
$ ocamlc -c main.ml File "main.ml", line 4, characters 13-22: Error: Unbound value multifact
ふむふむ。
それでは修正してみよう。main.ml
から multifact
を呼ぼうとしている箇所をコメントアウトして、
(* main.ml *) open Fact let () = print_int (fact 10); print_newline (); (* print_int (multifact 2 10); print_newline (); *) print_int (doublefact 10); print_newline (); ;;
コンパイルすると、今度は無事通った。
$ ocamlc -c main.ml # main.cmo が生成される $ ls . .. fact.cmi fact.cmo fact.ml fact.mli main.cmi main.cmo main.ml
これで必要なファイルが揃ったので、以下のように -o
オプションで実行ファイルを出力する。
$ ocamlc -o fact10 fact.cmo main.cmo $ ./fact10 3628800 3840
あるいは、以下のようにして最初から実行ファイルを出力することも可能。この場合もコンパイラには *.mli
を先に渡す必要あり。
$ ocamlc -o fact10 fact.mli fact.ml main.ml
先のエントリで見たようにシグネチャを書かなくても *.ml
から *.cmi
が生成されていた。この場合は、モジュールの中身は全て公開されることになる。
まぁ OCaml プログラマが意図的にシグネチャを書かないというケースはなさそう(想像)だから、気にしなくていいんじゃないかな。
(last update: 2017/09/23)
前回の続き。
$ ocamlc -o fact10 fact.ml main.ml
コンパイラ ocamlc
や ocamlopt
に -o
オプションで実行ファイル名を指定してソース・ファイル .ml
を渡すと実行ファイルが出力される。また .cmo
や .cmi
などのファイルも生成される。
で、これは恐らく手順をスキップしているというか、コンパイラがよしなにやってくれている。順をおって一手ずつ進めるとしたらこうなる。
まずソースファイル .ml
だけの状態から
$ ls . .. fact.ml main.ml
fact.ml
をコンパイルする。(-c
オプションを指定すると実行ファイルを作らずコンパイルだけする)
$ ocamlc -c fact.ml $ ls . .. fact.cmi fact.cmo fact.ml main.ml
次に main.ml
をコンパイルする。
$ ocamlc -c main.ml $ ls . .. fact.cmi fact.cmo fact.ml main.cmi main.cmo main.ml
このように 1 つずつコンパイルする場合も main.ml
から先にコンパイルしようとするとエラーになった。依存される側(参照される側)から先にコンパイルする必要がある。
File "main.ml", line 1, characters 5-9: Error: Unbound module Fact
で、オブジェクトファイル .cmo
をコンパイラに渡して実行ファイルを出力する。
$ ocamlc -o fact10 fact.cmo main.cmo $ ls . .. fact.cmi fact.cmo fact.ml fact10 main.cmi main.cmo main.ml $ ./fact10 3628800
ちなみに .cmo
を渡す場合も依存関係を無視してはいけない。main.cmo
を先にするとエラーになる。
$ ocamlc -o fact10 main.cmo fact.cmo File "_none_", line 1: Error: Required module `Fact' is unavailable
コンパイラは賢いから人間がソースファイルを渡して「実行ファイルを作って」とお願いしてもやってくれるけれど、ソースファイルからオブジェクトファイルを生成して、それを結合して実行ファイルを作成するというのが本来の手順なのだろう。
でも、同じ結果が得られるなら最初から実行ファイルを作成した方が早いだろうし -c
オプションはいつ使うのかという疑問がわく。
それは恐らく、もっと大きくて複雑なソフトウェアを作る場合には全体をパーツごとに分解して作っていくので、そういうときには、
ある部分は既にコンパイル済みの状態(オブジェクトファイル)で、 一部分だけコンパイル(ソースファイル -> オブジェクトファイル)し直して、 既にあるオブジェクトファイルと組み合わせて実行ファイルを作成する
という使い方をしたりするので必要、というか必須なのだと思う。(想像)
上記ではバイトコードコンパイラ ocamlc
での結果を書いたが、ネイティブコードコンパイラ ocamlopt
で試した場合も同様の結果になった。
インストールとか環境構築については今度書くとして、今日はコンパイルについて。
OCaml をインストールすると標準で 2 種類のコンパイラがついてくる。
ocamlrun
が必要(これも標準でついてくる)サンプルとして階乗を求める関数 fact
と、
(* fact.ml *) let rec fact n = if n = 0 then 1 else n * fact (n - 1)
それに引数 10 を渡して実行した結果を表示するプログラムを書く。
(* main.ml *) open Fact let () = print_int (fact 10); print_newline()
コンパイルして実行ファイルを作成するには以下のように入力する。-o
オプションで実行ファイルの名前を指定する。
$ ocamlc -o fact10 fact.ml main.ml
コンパイルすると実行ファイル fact10
と fact.cmi
, fact.cmo
, main.cmi
, main.cmo
というファイルが生成され、fact10
を実行すると結果が表示される。
$ ./fact10
3628800
しかし、ocamlc
に渡す順番を逆にするとエラーになる。
$ ocamlc -o fact10 main.ml fact.ml File "main.ml", line 1, characters 5-9: Error: Unbound module Fact
これは main.ml
の中で fact.ml
で定義されている関数 fact
を参照している、つまり main.ml
は fact.ml
に依存しているからである。
ocamlc
と同様に -o
で出力するファイル名を指定する。
$ ocamlopt -o fact10 fact.ml main.ml
実行ファイルの他に生成されるファイルが ocamlc
の場合とは一部異なった。
ocamlc
では fact.ml
から fact.cmi
, fact.cmo
が生成されたのに対して、fact.cmi
は同じで、fact.cmo
の代わりに fact.cmx
と fact.o
が生成されていた。
この *.cmi
, *.cmo
, *.cmx
, *.o
とやらは何だろうか。こういう普段見慣れないファイル形式が一度に複数出てくると、ウッてなるんだよね。落ち着いてマニュアルを見てみる。
.cmi
とは*.mli
をコンパイルすると *.cmi
が出力される
*.mli
が無い場合は *.ml
から *.cmi
が生成されるocamlc
でコンパイルした *.cmi
と ocamlopt
でコンパイルした *.cmi
は同一.cmo
とは.o
とは.cmx
とはプログラミング in OCaml 〜関数型プログラミングの基礎からGUI構築まで〜
上述の ocamlc
と ocamlopt
はバイトコードでコンパイルされたコンパイラのようで、ネイティブコードでコンパイルされたものもあり、通常はこちらを使うらしい。
ocamlc.opt
ocamlopt.opt
ネイティブコード にコンパイルされた バイトコード および ネイティブコード コンパイラ。 ネイティブコード コンパイルが可能な環境では通常このコンパイラを使う。
OCaml コンパイラソースで make opt の後に make opt.opt を行うと作成される。 通常の ocamlc, ocamlopt は バイトコード で実行されるが、 *.opt コンパイラはネイティブコードに コンパイルされているため ocamlc, ocamlopt よりコンパイル速度が早い。 (バイトコード版コンパイラがひどく遅いわけではないが。)
ocamlc, ocamlopt 以外の OCaml のツールにも、.opt の suffix がついた ネイティブコードバージョンが存在するのでそちらを使ったほうがよい。