Island Life

2014/01/29

関数型料理

関数型プログラミングを料理の仕方でたとえてください

関数型プログラミングを料理の仕方でたとえてください。
作る料理はなんでも構いません。
料理の一般的なレシピというのは、手続き型プログラミングで
たとえることが可能だと思っています。

「料理の仕方」と言ってしまった時点で手続き型思考の罠にはまってる気がする。

関数型の雰囲気だと、それは「料理の定義」に近いものになりそう。

  • ペペロンチーノとは、「炒めたにんにくと唐辛子」と「茹でたパスタ」を混ぜたものである
  • 「炒めたにんにくと唐辛子」は、「薄切りにんにく」と「輪切り赤唐辛子」をオリーブオイルで弱火にてxx分間炒めたものである
  • 「茹でたパスタ」は乾燥パスタを湯に入れxx分経過したものである
  • ...

っていう具合。

「手順」は陽に示されてないけど、そこは処理系がうまいことこの定義に従うように よろしくやってくれる。

パスタを茹でることでパスタの状態を変化させる、とは考えない。乾燥パスタを「茹でる」 操作の入力に与えると、出力に「茹でたパスタ」が得られる、と考える。 元のパスタは無くなるんだから変化してるじゃないかって? いやここでは時間もパラメータであって、時刻T1にスタートしてT2に茹で上がったとすると、 「T1に乾燥パスタがある」という状態はパスタが茹で上がった後でも不変だ。 現実世界ではタイムマシンがないからその状態にもうアクセスできないってだけで。

レシピが手順書の形を取っているのは、 人間がやる場合はいちいち頭の中で手順を考えるより、「コンパイル結果」である手順書を 逐次フォローしていった方が楽だからだろう。

ただ、単一の料理でなく一回の食事の準備という観点では、人は 「今日の夕食は、ご飯と肉じゃがとおひたしと昨日の残りの…」などど 定義を考えてからon-the-flyでコンパイルしつつ並列処理で仕上げるので、 その点については実は関数型言語の動作に近いかも。

Tag: Programing

2014/01/29

小切手による預金の移動

A銀行にある自分の口座から、B銀行にある自分の口座に預金を移したい、という場合。 日本だとATMで振込だろうけど、 こちらではA銀行の小切手の宛先を自分にしてB銀行に送っている。 電信送金もできるけど手数料かかるし、 最近は改善されたかもしれないが以前は何日かかかっていたので、 どうせ時間がかかるなら手数料不要な小切手送付でいい。

USに来た時から使ってる銀行が、ハワイから撤退してしまったので、 その銀行に預金するにはいずれにせよリモートな手段を使わざるを得ないし。

で、大抵いつもはハワイで小切手を投函して(宛先はアリゾナにあるバンキングセンター)、 3~4営業日で口座に反映されていたのだけれど。

1/13に送った分がなかなか反映されない。配送が遅れて週末に間に合わなかったとすると 翌週月曜がMartin Luther King's Dayで休みだったからそのせいかなと思って もうちょっとだけ待ったんだけど、10日経っても反映されないのでちょっと焦った。 配送途中で紛失されたなら、振り出し元の小切手を無効化すれば金が無くなることはないんだけど、 それとは別に月末のいろんな支払いの前に入金されていてくれないと残高が足りなくなるのだ。

慌てて1/24に新しい小切手を送付。

今朝オンラインでチェックしたら昨日づけで13日に送った分が入金されてて、24日に送った分も 処理中になってた。新しい小切手がきて慌てて前の分も処理したみたいにも見えるけど、 まあ単純にバックログがたまってたとか、誰かの机の端に置き忘れられてたとか、 そんなとこだろう。

迅速な処理はもともと期待してないんで良いのだが、 さすがにもうそろそろ小切手から移行すべきかなあ。電話料金やクレジットカードの 支払いはオンラインに移行済みだし。 銀行間預金移動がオンラインで手数料かからないかどうか調べてみよう (面倒で調べてない)。

Tag: 生活

2014/01/28

本日のyak shaving

  1. そろそろequal?をcircular-safeにするか。素直にAdams&Dybvigの論文を実装すればいいだろ。
  2. boxを使ってるな。pairで代用してもいいけど、Gaucheは既に内部的にはboxが用意されるんで この際だから使っちゃおう。
  3. Schemeに見せるインタフェースはsrfi-111でいいな。
  4. あれ動かない。あ、そうか、今のboxはコンパイラで楽するために暗黙のunboxという 変なことをやってたんだった。これを直さないと (WiLiKi:Gauche:boxに関する覚書)。
  5. BOXインストラクションのパラメータを変えて、と。おっと、インストラクション仕様が ビルド用Gaucheとターゲット用Gaucheで違ってるとエラーになるのか。 まずこのケースをサポートしないと。
  6. 5.のfixをコミット
  7. 4.のfixのうち仮引数のbox化をコミット
  8. 4.のfixのうちLOCAL-ENV-CLOSURESの変更に着手するも、これで作られるフレームで set!されてるlvarをbox化してなかったことに気づく
  9. 8.のfixをコミット
  10. 4.のfixのうち、UNBOXの明示化に着手
  11. むー動かない。まてよ、このGaucheをコンパイルしてるのは一つ前のGaucheで、 そいつはUNBOXインストラクション出さないんだから、LREFから暗黙のunboxを 落としちゃったら動作しないんじゃないか←イマココ

Tags: Programming, Gauche

2014/01/25

ピアノレッスン116回目

仕上げ手前で足踏み状態

  • Kapustin: Concerto Etude Op40-1
    • 「こういう音を出したい」と思って弾いてもピアノが違うと思っている音にならない、 そのときに崩れちゃうなあ。
  • Ravel: Ondine
    • 後半も良くなった。だがミスをなくそう。

Tag: Piano

2014/01/19

行継続

行指向の文法、つまり改行が単なる空白文字より大きな区切りを意味する文法において、 編集上の都合から見た目の行を折り返したい場合がある。 多くの場合は、行末に「次の行に継続する」ことを指示する文字を置くことで実現される。 行末バックスラッシュが多いのはUnixとC文化かな。 Common Lispのformat文字列では~。Fortranは&。Texinfoは@。 Visual Basicではアンダースコアだったっけ。

一方Vim Scriptでは、行末に文字を置くのではなく、継続する行の先頭に文字を置くよ、 という話を読んだ。

本当にキモい Vim script - 行継続編

さて、では一方 Vim script は、と言うと…

let g:quickrun_config = {
\   '_': {
\     'input': '=%{b:input}', 'cmdopt': '%{b:cmdopt}', 'args': '%{b:args}',
\     'runner': 'vimproc',
\     'runner/vimproc/updatetime': 500,
\   },
\ }

viとの互換性が理由だそうだ。

が、「次の行の方に前行からの継続を示すマーカがある」という文法を扱ったことが 何回かあるような気がしたので考えてみた。

RFC822のヘッダは原則1行で完結するけれど、次の行が空白文字で始まっている場合は それが継続行とみなされる。

Subject: Long subject line
  can be folded
  like this.

WiLiKiのマークアップは、行頭の ~ で前の行からの継続を示す。

強調などのマークアップは行をまたげないので、'''長い行をこんなふうに
~強調したかったら行継続を使う'''。

なぜこうしたのか忘れちゃったけど、wikiマークアップは「行頭にあること」 で意味を持つものが多いのでそれに合わせたのかも。

プログラミング言語で「次行行頭」にマーカを置く例はなかなか見つからない。 COBOLが "-" を「リテラルを前の行から継続」に使ってるけれど、 '-'を書くカラムが決まってるから「行頭」と言えるかどうか。

http://cobol.404i.com/basics.php

000340       DISPLAY 'This might be a very long string that
000350-    'needs to be continued onto the next line'

この表記を見てFTPのリプライ行継続マーカ (あれも-だ) を思い出したが、 FTPの方は「次に続く行がある場合」につけるので、「行末継続文字」グループの 親戚みたいなもんだろう。

★ ★ ★

技術的な観点では、「前の行から続いているよ」というマーカよりは、 「まだ行が続くよ」の方がパーザが書きやすい。前者では 次の行を読んでみないと今の行が終わるかどうかわからないので、 先読み、もしくはバッファリングが必要になる。

ただ、人間が普通のテキストを読み書きする際には、「まだ続くよ」マーカは あまり使われない。「行」が意味を持つ文章で、組版の都合でどうしても 行途中で折り返さないとならない時は、継続行がインデントで示されるのが普通だ。

Their sense thus weak, lost with their fears thus
  strong,
Made senseless things begin to do them wrong;
For briers and thorns at their apparel snatch,
Some sleeves, some hats, from yielders all things
  catch.

これは手元にあったペーパーバックからフォーマットをそのまま引用したものだけど、 "strong" や "catch"が前行からの継続であることは自然にわかる。 RFC822形式はある意味「人間にとって自然な記法」と言えるかもしれない。

「行の継続」だけでなくもう少しスコープを広げると、 結局先読みやバッファリングが必要になる構文はそこそこある。

  • Makefileのタブを使う文法は今となっては古くさいけれど、あの行頭タブは ひとつのルールのブロックを継続するマーカと言える。
  • インデント指向な文法でも、次の行のインデントを読んでみないと 今のブロックが終わるかどうかはわからない。

なので、パーザの書きやすさを理由に「次の行に続くよ」式文法を採用する意味は あまり大きくないかもしれない。

★ ★ ★

行継続構文についてもうひとつ考えるべき問題は、行をくっつけた時の「糊」の部分を どうするか、である。トークンの区切りとしての空白は何個あっても意味が変わらないので ただ行をくっつけるだけで良いが、リテラルの中で改行している場合は空白の個数が 意味を持ってくる。

「ただくっつける」という動作の場合、リテラル中に余分な空白を入れたくなければ、 次の行を行頭から始めないとならない:

  str = "This is a string \
literal"

けれども、意味的にインデントを揃えたいと思うのが人情だろう:

  str = "This is a string \
         literal."

このため、「次に来る行の行頭の空白を全て無視する」としている仕様もある。 Schemeの文字列リテラルや、Common Lispのformat文字列の ~がそうだ。

(define str "This is a string \
             litreral.")

しかしこれはこれで、「出力の行頭に一定数のスペースを含めたい」って時に ややこしい。例えばこんな出力が欲しいとき:

Usage: command [-a arg] [-b arg] file ...
Options:
   -a arg    Blah blah blah
   -b arg    Blah blah blah

物理行の先頭でインデントしててもその空白が食われてしまうので、 必要な空白の前に空白でない何かを置いとかないとならない:

(define (usage)
  (display "Usage: command [-a arg] [-b arg] file ...\
            \nOptions:\
            \n  -a arg    Blah blah blah\
            \n  -b arg    Blah blah blah\
            \n"))

Common Lispのformat文字列では「次の行の空白を保存する」という オプションもあるが、プログラムテキスト上の意味的なインデントと 出力に含めたいインデントを区別できないので、ちょっと足りてない感じだ。

「後続行に、前から続く行であることを示すマーカを入れる」という文法であれば、 空白文字以外のマーカを使うことでこの問題を解決できる。 たとえば仮想的に、行頭の\s*~が「前の行からの継続」を示す、 という文法があるなら、こんなふうに書けるだろう。

(define (usage)
  (display "Usage: command [-a arg] [-b arg] file ...\n
           ~Options:\n
           ~  -a arg    Blah blah blah\n
           ~  -b arg    Blah blah blah\n
           ~"))

リテラルに関してこれに近いことをやっていた言語があったような気もするのだけど 思い出せない。

なお、「人間にとって自然」に見えるRFC822の行折り返しだが、空白文字の扱いについて 微妙な点がある。英文の慣習では、\s*\n\s+ がひとつの空白に置換され、 RFC822もそれに沿っているわけだが、この文法だと「空白を含めずに折り返す」 というケースが書けない。Subjectヘッダの扱いに関して困った覚えがある。 (MIMEを用いても、各MIMEエンコーディングは物理行内で完結しないとならないので、仕様に厳密に従うと行継続の空白が残ってしまうのだ。実際のメールクライアントはそのへんヒューリスティックに対応しているっぽいが。 (追記2014/01/20 06:06:20 UTC)これは私の誤解だった。rfc2047の6.2節にてこのケースへの対応が示されている。コメント欄参照。) なので、「継続を示すマーカ」は空白文字とか区別できる方がいい。

特に結論めいたものはないけれど、新たな文法を考えるなら、 少なくともリテラルの行継続については、「行頭の <空白>* <非空白文字のマーカ>」というのは 案外良い選択なんではないかな、と思った。

Tag: Programming

More entries ...