タグ

ブックマーク / rainyday.blog.ss-blog.jp (17)

  • ユーザー定義のdistfix/mixfix演算子をパースする:Rainy Day Codings:So-net blog

    プログラミング言語で演算子というと普通は中置演算子(infix)だが、C言語の++のように前置演算子(prefix)や後置演算子(suffix/postfix)もある。 ?:のような演算子はどうかというと3項演算子(tertiary operator)と呼ばれる。 この言葉は3という数字に限定されているし、syntacticな特徴―複数要素から成り、間に被演算項が入る―を表現していない。(f(x,y,z)の形でも3項ではある) もっと一般的にはどういうのかというと、プログラミング言語の世界ではdistfixまたはmixfixというようだ。[^1] 中置演算子もそうだが、distfixを任意の識別子に対して任意の優先度でユーザー定義できるようにしようとすると、パーサーの動作を動的に変更する必要が出てきて結構大変になる。 一方で、それらの演算子をlexicalに区別できるようにして優先度も固定

  • OCaml:Rainy Day Codings:So-net blog

    入力ストリームの実装から独立したパーサーを定義したい。 そこでまずは入力ストリームのデータ型を定義する。 module type INSTREAM = sig type instream (* 当はinstreamに対する色々な操作を含むつもり *) end 実際の入力元はチャネルだったりメモリ上の文字列だったりする。 module ChanIns = struct type instream = in_channel end module StringIns = struct type instream = string end パーサーのシグニチャと実装はこんな感じになる。 module type PARSE = sig type instream type result val parse : instream -> result end module Parse(I: INSTR

  • 初めて再帰モジュールが必要になった話:Rainy Day Codings:So-net blog

    入力ストリームの実装から独立したパーサーを定義したい。 そこでまずは入力ストリームのデータ型を定義する。 module type INSTREAM = sig type instream (* 当はinstreamに対する色々な操作を含むつもり *) end 実際の入力元はチャネルだったりメモリ上の文字列だったりする。 module ChanIns = struct type instream = in_channel end module StringIns = struct type instream = string end パーサーのシグニチャと実装はこんな感じになる。 module type PARSE = sig type instream type result val parse : instream -> result end module Parse(I: INSTR

    nfunato
    nfunato 2016/10/13
    "recursive module"
  • 幽霊型を使ってウェブアプリで安全に文字列を使う:Rainy Day Codings:So-net blog

    以前 Joel on Software の「間違ったコードは間違って見えるようにする」という記事 [1] を読んだ。彼はこの記事の中でハンガリアン記法のうち変数のデータ型/タイプ (type) を示すに過ぎない「システムハンガリアン」を否定する一方で、タイプでは区別できないような種類 (kind) を示す「アプリケーションハンガリアン」を支持している。 この記事にはとても感心したのだけど、彼の出している「安全な文字列」と「安全でない文字列」の例をみてこうも思った。このくらいのことなら面倒見てくれるコンパイラやツールがあったっていいんじゃないだろうか。種類とタイプの違いというのは先験的にあるもの(と Joel Spolsky が書いているわけではないが)じゃなくて、コンパイラや IDE などのツールがサポートするところまでがタイプで、残りが種類なんじゃないだろうか。 とはいえ、口で言えても実

    nfunato
    nfunato 2016/10/13
    "opaque type"
  • Camomile 使い方メモ:Rainy Day Codings:So-net blog

    Camomile について調べたメモ。 普通の文字列型 (string) と Camomile 内部のユニコード文字列型との間の変換を行うエンコーダ/デコーダを作る。内部エンコーディングとして UTF-8 を使う場合は以下のようにする。UTF8 以外にも UText, XString, UTF16, UCS4 が選べるようだ。 KURO-BOX% ocaml bigarray.cma camomile.cma Objective Caml version 3.10.0 # module U = CamomileLibrary.Default.Camomile.CharEncoding.Make(CamomileLibrary.UTF8);; module U : sig type text = CamomileLibrary.UTF8.t val decode : CamomileLibr

    nfunato
    nfunato 2016/10/13
    "camomile"
  • Camomile 使い方メモ (2):Rainy Day Codings:So-net blog

    Camomile についてさらに調べる。 Camomile のユニコード文字列型には何種類かあるけれども文字型は UChar という1つしかない。 特定のエンコーディングで書かれたテキストファイルから読み込むには以下のようにする。hyoji.txt は Shift_JIS で「表示」の2文字だけが書かれたファイルとする。 # let inc = open_in "hyoji.txt";; val inc : in_channel = <abstr> # let sjis = CamomileLibrary.Default.Camomile.CharEncoding.of_name "SHIFT_JIS";; val sjis : CamomileLibrary.Default.Camomile.CharEncoding.t = <abstr> # let inc' = new Camomi

    nfunato
    nfunato 2016/10/13
    "camomile"
  • ユニコード文字列のリテラルを使う:Rainy Day Codings:So-net blog

    抽象データ型とリテラルというのがそもそも相容れないのかもしれないが Camomile の文字列型にはリテラルがない。ソースを書いた時点で固定的な情報をランタイムに計算するのはちょっと癪なのでいろいろ考えてみたのだけど、結局文字列型としては UTF8.t を、リテラルとしては通常の OCaml の文字列リテラルを使って abstraction barrier を破って UTF8.t と認識させるのが一番簡単であろうという結論に達した。 ただしこれだとソースファイルも UTF-8 で書かないといけないという問題がある。これを解決するために Java でいう native2ascii のような簡単なツールを作った。 (* wchar2latin.ml *) open CamomileLibrary.Default.Camomile;; open CamomileLibrary.Default.C

    nfunato
    nfunato 2016/10/13
    "camomile"
  • 分数を小数に展開と桁あふれと OCaml Sucks:Rainy Day Codings:So-net blog

    無い知恵を絞って「どう書く?org」の「分数を小数に展開」という問題 [1] にOCaml で投稿してみた [2]。 投稿した後で別の方が「2147483645 / 2147483647 で~」と書いていたので、そういえば問題文の境界値 2^31-1 は OCaml の int では満たせないんだったと気がついたのだけど、じゃあ 2^30-1 の 1073741823 までならできるんだっけと思ってやってみると、 # pretty_fmt (decimal_of_frac 1073741823 1073741823);; - : string = "1." # pretty_fmt (decimal_of_frac 1073741823 1073741822);; - : string = "1.00000000000000000000000000000-1{000000000000000

  • printf 続き:Rainy Day Codings:So-net blog

    前回 [1] の myprintf は2引数をとる関数だったから部分適用できる。 # let f = myprintf "%s";; val f : '_a -> unit = <fun> '_a という、これまた馴染みのない型が出てきた。 調べてみるとこれは多相型ではなくて、まだ型が決まっていないというだけの状態を示すものらしい。続けて以下のように打ち込む。 # f "hello!";; hello!- : unit = () そしてもう1回 f の型を確認してみる。 # f;; - : string -> unit = <fun> さっきとちがう。一度関数が完全に適用されると型が確定して string になるということのようだ。こうなると文字列以外を与えて f を呼び出すとコンパイルエラーになる。 # f 123;; Characters 2-5: f 123;; ^^^ This e

  • 可変長引数の書式付バイナリ出力関数:Rainy Day Codings:So-net blog

    OCaml の printf 関係で検索していたら Caml-list の過去ログ [1] で紹介されていた論文 [2] に ML で printf っぽいものを作る一つのやり方が書いてあった。(ちなみにそのスレッドのフォローアップに OCaml には special typechecking rules for format strings があるようなことが書いてあるのでやはり printf は特別ということらしい) さて、[2] を参考に見よう見まねで当初の目的であった書式化バイナリ出力関数を作ってみた。fout というのが作りたかった関数だ。 # let ($) f g x = f (g x);; val ( $ ) : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b = <fun> # let a k s x = k (output_string s x

  • (可変長の)書式付バイナリ入力関数:Rainy Day Codings:So-net blog

    前回 [1] はバイナリ出力関数を作ったけど入力のほうを作っていなかった。 入力のほうは読み込んだ値をどのように取り出すかで何通りかの実装が考えられると思う。思いついた順に3種類のコードを載せる。 まずは参照を使う方法。これは出力版をひっくり返しただけでシンプルだ。 let ($) f g x = f (g x) let a len k s x = let buf = String.make len ' ' in really_input s buf 0 len; x := buf; k s let c k s x = k (x := input_char s; s) let b k s x = k (x := input_byte s; s) let i k s x = k (x := input_binary_int s; s) let fin ich p = p (fun s ->

  • OCaml:Rainy Day Codings:So-net blog

    「ふつうのHaskell」によると Haskell には words 関数というのがあってこういうふうに使うらしい。 Prelude> words "This is a pen" ["This","is","a","pen"] OCaml には似たような関数はないようなのでこれを作ってみる。 Haskell の words は「文字列 -> 文字列のリスト」だけど、「ストリーム -> ストリーム」で作ってみた。 以下の words のストリームビルダーの関数は呼ばれるとまずストリームの最初の空白を除去して最初の一語を切り出して返す。 let stdinstr = Stream.of_channel stdin;; let words str = let is_space c = String.contains " \t\r\n" c in let rec trim_leading char

  • Stream と cat コマンド:Rainy Day Codings:So-net blog

    「ふつうの Haskell」を買ったので OCaml の実用レッスンをするのにちょうどよさそうな問題をこの中から探して OCaml に書き換えて実装してみようと思う。 まずは cat コマンド。といっても標準入力から読んで標準出力へ出すだけの簡易版。Ocaml だとこんな感じだろうか。 let _ = let stdinstr = Stream.of_channel stdin in Stream.iter print_char stdinstr ;; Stream.of_channel は入力チャネルからストリームを作って文字の列のストリームを作る。 stdin から作ったその入力ストリームの1文字1文字に対して print_char を適用するので標準入力から標準出力へ1文字ずつ流すということになるわけだ。 実際のプログラミングでは行単位で処理を行うことが多いだろう。行単位のストリーム

  • EOPL と異なる再帰関数実装:Rainy Day Codings:So-net blog

    EOPL の再帰関数の実装について sumii さんがさらなる alternative な実装について書かれています。 [1] http://d.hatena.ne.jp/sumii/20071105/p1 [2] http://d.hatena.ne.jp/sumii/20071107/p1 大変ためになったので理解するためにコードを写経してみました(後掲)。 写経しているうちに [2] のほうの記事の「整数とクロージャの組」は整数をクロージャのレコードに含めてしまうほうが簡潔なのではという気がしてきたのでそう変えてみました。 こうすると (if (and (pair? proc) (number? (car proc)) (procval? (cdr proc))) ...) みたいな箇所は (if (procval? proc) ...) でよくなるほか、あまり car とか cdr

    nfunato
    nfunato 2016/10/05
  • OCaml + sexplib で Scheme もどきを作る:Rainy Day Codings:So-net blog

    よく Scheme や Lisp ので Scheme/Lisp を使って Scheme/Lisp 処理系を書くというのがあって大層簡潔に書いてあったりするのですが、これは要するに S 式リーダ機能がビルトインで存在するというのが有利に働いているので、他の言語でも S 式を簡単に読めれば同じくらいにはできそうです。 そこで OCaml の sexplib [1] を使ってみたかったこともあって、それを使ってなんちゃって Scheme を書いてみました。 なお sexplib は「産業界における関数型言語の事例」でよく引き合いに出されている Jane Street Capital で開発された OCaml 向けの S 式ライブラリです。 #use "topfind";; #require "sexplib";; #require "extlib";; open ExtList;; open

  • ラムダ文字の由来:Rainy Day Codings:So-net blog

    Haskell で匿名関数を表現するのに \ を使うのはバックスラッシュがラムダ文字 λ に似てるかららしい。でもこれは Windows とかだと円記号になってしまって台無しである。それにバックスラッシュは相当多くの言語で一意にエスケープの意味を持つので混乱する。 匿名関数をラムダ lambda と呼ぶのは Lisp の影響だが、Peter Norvig の Paradigms of Artificial Intelligence Programming によると Lisp で匿名関数を lambda と書くのは以下のような由来らしい。 - Russel と Whitehead の Principia Mathematica では のように束縛変数の上にキャレットを置く書き方をしていた - Church がその記法を ^x(x+x) と変えた - キャレットの下に何も無いのが変だと思ったの

    nfunato
    nfunato 2014/06/08
  • Prolog で型チェック:Rainy Day Codings:So-net blog

    Prolog の力といえば単一化ですが、[1] の記事でやったような型チェックの場合も、同じ型であるかどうかの判断というのは単一化でうまく書けそうです。 型チェックのところだけ書きたいので構文木は適当に与えられているものとします。 整数と真偽値と条件分岐と変数束縛とラムダから成る簡単な言語を想定して Prolog で型チェックを行ってみます。 type_of(Num, _, number) :- number(Num). type_of(true, _, bool). type_of(false, _, bool). type_of(if(Cond, True, False), Env, T) :- type_of(Cond, Env, bool), type_of(True, Env, T), type_of(False, Env, T). type_of(let(Sym, Val, B

  • 1