Good Luck! x Typed Scheme x Curried Typed Scheme

最近、「Typed Scheme」とやらが話題を呼んでいるようです(http://www.ccs.neu.edu/home/samth/typed-scheme/ 参照)。「Scheme」言語に型を付けて、「Haskell」言語らしくする手法です。そうすれば、バッグをより解消しやすくなるそうです。

面白そうだったので、試しに作ってみました。先ず、普通のPLT Scheme言語で「good-luck.ss」という、ユーザー名によって出力するメッセージを変える手続きを作りました:

;; good-luck.ss
;; PLT-Scheme-specific program to wish a person good luck
;; 
;; Copyright(C) October 20, 2008, at 13:42, 
;; by Benjamin L. Russell

#lang scheme

(define (good-luck name)
  (if (string=? name "Nobody")
      (printf "You are ~a." name)
      (good-luck-helper name "Good Luck")))

(define (good-luck-helper a b)
  (printf "~a, ~a!" a b))

上記のSchemeソースコードを実行するには、先ず、DrScheme(http://www.csg.is.titech.ac.jp/~kourai/lecture/drscheme/drscheme.htmlhttp://download.plt-scheme.org/ 参照)をダウンロード・インストールし、その後、例えば、

(good-luck "Benjamin")

と入力すればいいのです。そうすれば、

Benjamin, Good Luck!

と返ってきますし、また

(good-luck "Nobody")

と入れると、

You are Nobody.

と返ってきます。

これだけでは面白くないので、今度はこれを「good-luck-typed.ss」という「Typed Scheme」の手続きに翻訳してみました:

;; good-luck-typed.ss
;; Typed Scheme version of good-luck.ss program to wish a person good luck
;; 
;; Copyright(C) October 20, 2008, at 13:46, 
;; by Benjamin L. Russell

#lang typed-scheme

(: good-luck-typed (String -> Void))
(define (good-luck-typed name)
  (if (string=? name "Nobody")
      (printf "You are ~a." name)
      (good-luck-helper-typed name "Good Luck")))

(: good-luck-helper-typed (String String -> Void))
(define (good-luck-helper-typed a b)
  (printf "~a, ~a!" a b))

主な変更点は「#lang typed-scheme」が加わったところと、「(: good-luck-typed (String -> Void))」と「(: good-luck-helper-typed (String String -> Void))」が追加された点ですね。

「good-luck-typed」はString型のパラメーターを入力とし、何も返さない(つまり、「Void」を返す)。「good-luck-helper-typed」はString型のパラメーター二つを入力とし、同じく何も返さない(つまり、また「Void」を返す)。

さて、結果はどうでしょう?

> (good-luck-typed "Benjamin")
Benjamin, Good Luck!
> (good-luck-typed "Nobody")
You are Nobody.
> 

なるほど、結果は同じですね。

本来なら、ここでバグが発生した時の違いなどを説明したいところですが、時間がありませんので、これはまたの機会に致しましょう。

最後に、カリー化(http://ja.wikipedia.org/wiki/%E3%82%AB%E3%83%AA%E3%83%BC%E5%8C%96 参照)が可能なのか、好奇心がありました。では:

;; good-luck-curried.ss
;; Curried Typed Scheme version of good-luck.ss program to wish a person good luck
;; 
;; Copyright(C) October 20, 2008, at 17:44, 
;; by Benjamin L. Russell

#lang typed-scheme

(: good-luck-curried (String -> Void))
(define (good-luck-curried name)
  (if (string=? name "Nobody")
      (printf "You are ~a." name)
      ((good-luck-helper-curried name) "Good Luck")))

(: good-luck-helper-curried (String -> (String -> Void)))
(define ((good-luck-helper-curried a) b)
  (printf "~a, ~a!" a b))

主な違いは、「(: good-luck-helper-curried (String -> (String -> Void)))」と「(define ((good-luck-helper-curried a) b)」のそれぞれの変更点です。なるほどです、確かにカリー化されているようです。それにしても、「(: good-luck-helper-curried (String -> (String -> Void)))」の括弧のつけ方が右よりであるのに対し、「(define ((good-luck-helper-curried a) b)」の括弧のつけ方が左よりである点が少し気になりますね。

それはさておき(また時間がないので、後程に致しましょう)、結果はどうでしょう?

> (good-luck-curried "Benjamin")
Benjamin, Good Luck!
> (good-luck-curried "Nobody")
You are Nobody.
> 

なるほど、また結果は同じですね。

詳細なお話はまた次回の機会に。

あくまで、アマチュア関数型プログラミング研究者ですから・・・・・・。

Towers of Hanoi

お次は、Haskell言語版の「Towers of Hanoi」:

-- hanoi_v1.1.hs
-- Haskell function to compute the Towers of Hanoi problem recursively
-- 
-- Usage: putStr (hanoi_shower (hanoi 1 2 3 n)), or 
--        putStr (hanoi_shower (hanoi 'a' 'b' 'c' n)), 
--        where the first three arguments of hanoi may be polymorphic types
--        (i.e., Chars, Ints, or any other suitable type), and n is the number
--        of discs to move from the source peg to the destination peg
-- 
-- Copyright(c) April 16, 2008, at 14:17, 
-- by Benjamin L. Russell
-- 
-- Update History:
-- 
-- Version 1.0.1
-- Changed program name in comments:
-- "Hanoi.hs" -> "hanoi.hs"
-- 
-- Version 1.0.2
-- Corrected copyright date: April 17 -> April 16
-- 
-- Update History:
-- 
-- Version 1.1
-- Added usage information.
-- October 17, 2008, at 14:45

hanoi :: a -> a -> a -> Int -> [(a, a)]
hanoi source using dest n
    | n == 0 = []
    | n == 1 = [(source, dest)]
    | otherwise = hanoi source dest using (n-1) 
                  ++ hanoi source using dest 1
                         ++ hanoi using source dest (n-1)

hanoi_shower :: Show a => [(a, a)] -> String
hanoi_shower [] = ""
hanoi_shower ((a, b):moves) = unlines ["Move " ++ show a ++ " to "++ show b ++ "."] ++ hanoi_shower moves

上記のHaskellソースコードを実行するには、先ず、Haskellの主流コンパイラGHChttp://www.f13g.com/%a5%d7%a5%ed%a5%b0%a5%e9%a5%df%a5%f3%a5%b0/Haskell/%bd%e8%cd%fd%b7%cf%a4%ce%a5%a4%a5%f3%a5%b9%a5%c8%a1%bc%a5%eb/#content_1_5http://www.haskell.org/ghc/ 参照)をダウンロード・インストールし、その後、例えば、

putStr (hanoi_shower (hanoi 'a' 'b' 'c' 3))

と入力すればいいのです。そうすれば、

Move 'a' to 'c'.
Move 'a' to 'b'.
Move 'c' to 'b'.
Move 'a' to 'c'.
Move 'b' to 'a'.
Move 'b' to 'c'.
Move 'a' to 'c'.

と返ってきます。

どうです?これも簡単だが、またまた美しいでしょう!

では、今回はこの辺で・・・・・・。次回までお楽しみに。

あくまで、アマチュア関数型プログラミング研究者ですから・・・・・・。

Towers of Hanoi

初めて始めてみた、あくまでも、悪魔でも、開くまでも書き続けてみます!

では、アクマデ、アマチュア関数学的プログラミング研究者として、小生の「Towers of Hanoi」を掲載させて頂きます:

;; Towers of Hanoi, plt1.1
;; PLT-Scheme-specific Version 1.1 of Towers of Hanoi
;; 
;; Copyright(C) April 02, 2008, at 19:38, 
;; by Benjamin L. Russell

(define (hanoi n)
  (hanoi-helper 'A 'B 'C n))

(define (hanoi-helper source using destination n)
  (cond ((= n 1)
         (printf "Moving from disc ~a to ~a.\n" source destination))
        (else
         (hanoi-helper source destination using (- n 1))
         (hanoi-helper source using destination 1)
         (hanoi-helper using source destination (- n 1)))))

上記のSchemeソースコードを実行するには、先ず、DrScheme(http://www.csg.is.titech.ac.jp/~kourai/lecture/drscheme/drscheme.htmlhttp://download.plt-scheme.org/ 参照)をダウンロード・インストールし、その後、例えば、

(hanoi 3)

と入力すればいいのです。そうすれば、

Moving from disc A to C.
Moving from disc A to B.
Moving from disc C to B.
Moving from disc A to C.
Moving from disc B to A.
Moving from disc B to C.
Moving from disc A to C.

と返ってきます。

どうです?簡単ですが、素晴らしいでしょう!

では、今回はこの辺で・・・・・・。次回までお楽しみに。

あくまで、アマチュア関数型プログラミング研究者ですから・・・・・・。