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っぽいラムダ式がダンプされる。

適当な関数とマクロを定義してやれば、このまま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)))