OCaml on Scheme
30分プログラム、その376。OCamlが生成したラムダ式をScheme処理系の上で動かしてみる。
OCaml処理系には、その中間形式でらうラムダ式をダンプ機能がある。undocumentedと書かれているけど。
たとえば、こんなfact.mlを
let rec fact n = if n = 0 then 1 else n * fact (n - 1)
"-dlambda"付きでコンパイルすると
$ ocamlc -dlambda fact.ml (setglobal Sample! (letrec (fact/58 (function n/59 (if (== n/59 0) 1 (* n/59 (apply fact/58 (- n/59 1)))))) (makeblock 0 fact/58)))
適当な関数とマクロを定義してやれば、このままSchemeプログラムになるんじゃね?と思ったので試してみた。方針は、この階乗計算さえ動けばいい、といった感じで。
あとletrecとapplyは、Schemeのものと名前がかぶってややこしいので、手動でリネームすることにした。
使い方
;; -dlambdaした結果をペースト ;; ただしletrecをmy-letrec、applyをmy-applyに書き換え gosh> (setglobal Sample! ...) Sample! gosh> (fact/58 3) 6
ソースコード
#! /opt/local/bin/gosh ;; -*- mode:scheme; coding:utf-8 -*- ;; ;; 2008-09-27-222311.scm - ;; ;; Copyright(C) 2008 by mzp ;; Author: MIZUNO Hiroki / mzpppp at gmail dot com ;; http://howdyworld.org ;; ;; Timestamp: 2008/09/27 22:23:16 ;; ;; This program is free software; you can redistribute it and/or ;; modify it under MIT Lincence. ;; (define-syntax setglobal (syntax-rules () ((_ name body) (define name body)))) (define (makeblock x y)) (define-syntax function (syntax-rules () ((_ param body ...) (lambda (param) body ...)))) (define-syntax my-letrec (syntax-rules () ((_ (var body ...) rest ...) (begin (define var body ...) rest ...)))) (define == =) (define (my-apply f . args) (apply f args)) (setglobal Sample! (my-letrec (fact/58 (function n/59 (if (== n/59 0) 1 (* n/59 (my-apply fact/58 (- n/59 1)))))) (makeblock 0 fact/58)))