ãã®è¨äºã§ã¯, Haskellã«ç¨ãããããé 延è©ä¾¡ãã®ä»çµã¿ã, å³ã«æãã¦èª¬æãã¾ã. æ´ã«, é 延è©ä¾¡çã®ãã£ããããæ°ã®ç¡éåã, JavaScriptã§å®è£ ãã¾ã. é 延è©ä¾¡ã¨ã¯ã©ã®ããã«åãã®ã, èãã¦è¡ãã¾ããã.
Haskellã®ã³ã¼ãã¨JavaScriptã®ã³ã¼ãã®æ¯è¼
Haskellã§ã®
x = y y = 10
ã¨, JavaScriptã®
var x = y; var y = 10;
ã¨ããã³ã¼ããèãã¦ãã ãã. Haskellã®ã³ã¼ãã¯, ããã ãã§ã¯ä½ãèµ·ããã¾ãã. print xã¨ããã¨, x = y = 10 ã¨ãªã£ã¦ 10 ã表示ããã¾ã. ä¸æ¹, JavaScriptã®ã³ã¼ã㯠var x = y; ãè©ä¾¡ããç¬é, ï½¢ReferenceError: y is not definedï½£ã¨ããã¨ã©ã¼ãåºã¾ã.
æ´ã«,
main = let x = 10 in let x = x + 5 in print x
ã¨ããã³ã¼ãã¯, x ã®è©ä¾¡ãç¡éã«ã¼ãã«é¥ã£ã¦ä½ã表示ããã¾ãã.
JavaScriptã®
x = 10; x = x + 5; console.log(x);
ã¨ã¯, å ¨ãéã£ã風ã«åãã®ã§ã.
ä»ã®è¨èªã«æ
£ãã¦ãã人ã«ã¨ã£ã¦ã¯, Haskellã®è©ä¾¡ã¯å¥å¦ã«æããã¨æãã¾ã. ããã¯, Haskellãé
延è©ä¾¡ã¨å¼ã°ããè©ä¾¡æ¦ç¥ãã¨ã£ã¦ããããã§ã.
é 延è©ä¾¡ã¨ç¡éãªã¹ã, undefined
é 延è©ä¾¡ã®åãããããä¾ã¨ãã¦, ç¡éãªã¹ããèãã¦ã¿ã¾ã.
main = print [0..]
[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,...
ãã®ããã°ã©ã ã¯, 0 ããã®æ°ããã¼ã£ã¨è¡¨ç¤ºãç¶ãã¾ã.
ããã¯ä»¥ä¸ã®ããã«ãæ¸ãã¾ã.
main = putStrLn (show [0..])
show [0..]ã¨ããã®ã¯, ãç¡éãªã¹ãããè©ä¾¡ãã¦ç¡éã®é·ãã®æååã«ãªãã¾ã.
ã§ã¯,
main = let x = show [0..] in print (head x)
'['
ã¨ããã®ã¯ã©ãã§ãããï¼
x ã¯ç¡éã®é·ãã®æååã§ã.
ããã£ã¦ããããªãã§ããï¼
let x = show [0..] ã¨ããç¬éã«, show [0..] ã¨ããç¡éã®é·ãã®æååã®ä½ããã®æ
å ±ã x ã«æç¸ãããã®ã§ãã, ãã®æç¹ã§è©ä¾¡ã¯ãããªãã®ã§ã.
ããã¦, print (head x) ã¨ããç¬éã«, x ã®æåãå¿
è¦ã«ãªã£ã¦è©ä¾¡ããã®ã§ã.
take ã¨ããé¢æ°ãæãåºãã¦ä¸ãã.
main = let x = [0..] in print (take 10 x)
[0,1,2,3,4,5,6,7,8,9]
ãã®ããã°ã©ã ã, é
延è©ä¾¡ãå½¹ã ã£ã¦ãã¾ã.
let x = [0..] ã§ç¡éé·ã®ãªã¹ãã x ã«æç¸ã, ãã®ãªã¹ãããæåã®10åãå¿
è¦ã«ãªã£ã¦, ãããã ããè©ä¾¡ãã¦, print ãã¾ã.
ããä¸ã¤, undefined ãæãåºãã¾ããã.
main = undefined >> print "hello"
*** Exception: Prelude.undefined
ã¤ãã¤ãã¤ã§ãã.
è©ä¾¡ãããä¾å¤ãé£ãã§ããã°ã©ã ãã¹ããããã¾ã.
main = let x = undefined in print x
*** Exception: Prelude.undefined
ãã¡ãã, ããã.
ã§ã, 次ã®ããã°ã©ã 㯠undefined ãè©ä¾¡ããã¾ããï¼
main = let x = [undefined, undefined, undefined] in print (length x)
3
ããã«æ¬¡ãï¼
main = let x = undefined : x in print (null x)
False
ããã«
main = let x = undefined : x in print (length (take 10 x))
10
æ¬å½ã«, å¿ è¦ã«ãªãã¾ã§è©ä¾¡ãããªããã§ããï¼ï¼ï¼
let x = [0..] ã, let x = show [0..] ãªã©ã¯, ããèãããä¸æè°ãªå¼ã§ã.
ã©ããã£ã¦ç¡éé·ã®ãã¼ã¿ã x ã«æç¸ãããã¨ãã§ã, å¿
è¦ãªã¨ãã«è©ä¾¡ãããã¨ãã§ããã®ã§ãããã.
ããã«, let x = undefined : x ãªã©, undefined ã¯æ¬å½ã®æ¬å½ã«è¦ç´ ãå¿
è¦ã«ãªãã¾ã§ã¯, è©ä¾¡ããã¾ãã.
å¤ãå¿
è¦ã, ã©ããããå¿
è¦ãã©ããã£ã¦, ã©ããã£ã¦å¤å®ããã®ã§ãããã.
è©ä¾¡ããã¦ããªãæ§åãçµµã«æãã¦ã¿ãã
let x = 3 ã¨ããå¼ã¯, æã
ã®ç´æçãªä»£å
¥ã¨ã¯ç°ãªãã¾ã.
x ã¯, è©ä¾¡ããã 3 ã«ãªã, ä½ããªã®ã§ã.
ãã®ãä½ããã, åè§ã§å²ã£ã¦æãã¦è¡¨ãã¦ã¿ããã¨ã«ãã¾ã.
ã¤ã¾ã,
ãããªãã¦,
ã§ã.
ä½ããã®é¢æ° f, g ãããæ,
let x = f g 10
ã¨ããã®ã¯,
ã§ã¯ãªãã¦,
ã§ãï¼
ã¤ã¾ã, æ¬å¼§ãæ¸ããããªã¨ããã«ã¯å
¨ã¦åè§ã§å²ãã®ã§ã.
let x = (((f) (g)) (10))
ãã®çµµã®è¡¨ç¾ã使ã£ã¦, Haskell ã®è©ä¾¡ãã©ã®ããã«åãã¦ããã®ã確ããã¦ã¿ã¾ããã.
次ã®ã³ã¼ããèãã¾ã.
main = let x = 1 : x in print (null x)
ãããçµµã«æãã¦ã¿ãã¨
ã¨ãªãã¾ã.
æ¼ç®åã¯è¯ãæãã«ã»ã¯ã·ã§ã³ã¨ãã¦è¦ã¦ä¸ãã.
null ã®å®ç¾©ã¯ããã§ãã.
null :: [a] -> Bool null [] = True null (_:_) = False
JavaScriptã®nullã¨ã¯éã£ã¦, 空ãªã¹ããã©ããå¤å®ããé¢æ°ã§ãã.
ã¤ã¾ã, function (list) { return list.length === 0; } ã®ãã¨ã§ã (大ä½).
ãããç¨ããã¨,
print (null x) = print (null (1 : x)) = print False
ã¨ãªããã¨ãåããã¾ãã.
ãããçµµã§ç¢ºèªãã¦ã¿ã¾ããã.
ãè©ä¾¡ããããã¨ã¯, çµµã®ä¸ã§ã¯åè§ãå¤ããã¨ã«ãªãã¾ã.
äºé
æ¼ç®åã¯, æ¼ç®åããåè§ãå¤ãã¾ã.
ä½ã¹ããããçµã¦ç®±ãå¤ã, ãããã False ã¨è¡¨ç¤ºãããã¨ãã§ãã¾ãã (ã¾ãå³å¯ã«ã¯ã¡ãã£ã¨éãã¾ãã許ãã¦ãã ãã(๑´◕﹏◕`))
æå¾ããäºè¡ç®ã«æ³¨ç®ãã¦ä¸ãã.
ã1ãã, åè§ã§å²ãããã¾ã¾ã§ãï¼
ã¤ã¾ã, null é¢æ°ã¯æåã®è¦ç´ ãä½ã§ããããè©ä¾¡ããªãã®ã§ã.
ãã¡ãã null é¢æ°ã¯æå以å¤ãããå¿
è¦ãããã¾ãã.
ã ãããã, ãã®ã³ã¼ãã¯ãã¡ãã¨è©ä¾¡ãæ¢ã¾ããã§ã.
çµå±, ãã¼ã¿æ§æå (:) ã ã, è©ä¾¡åºæ¥ãã°ãããã§ãã.
ããã§æ¸ãããããªå³ã«ã¯, å¹¾ã¤ãã®ã«ã¼ã«ã«åºã¥ãã¦ãã¾ã.
- let x = hoge ã¨ããæ, hoge å ¨ä½ãåè§ã§å²ããã; x = [ hoge ]. ããã«ã¯è©ä¾¡ãããªã.
- åè§ã¯å¤å´ããå¤ã. åæã«å å´ã®åè§ãå¤ãã¦ã¯ãããªã.
- f x ã¨ããé¢æ°é©ç¨ã®åè§ãå¤ããå¾ã¯, f ã®æ¹ãå ã«è©ä¾¡ããã. ãã®å¾, x ã¯è©ä¾¡ãããªãã¾ã¾ f ã«é©ç¨ããã; [ [ f ] [ x ] ] -> [ f ] [ x ] -> f [ x ]. [ [ [ f ] [ g ] ] [ x ] ] -> [ [ f ] [ g ] ] [ x ] -> ([ f ] [ g ]) [ x ] -> (f [ g ]) [ x ].
- ãã¿ã¼ã³ãããã¯ãã¼ã¿æ§æåã§è¡ããã. ãã¼ã¿æ§æåãè©ä¾¡ãããæç¹ã§, ãã¿ã¼ã³ãããã§åå²ã, å¤æ°ã«ã¯è©ä¾¡ããã¦ããªããã¼ã¿ãæç¸ããã; [ [ T ] [ a ] ] -> [ T ] [ a ] -> T [ a ].
undefined ãå«ãã³ã¼ãã, ãã®çµµã®ä¸ã§ã©ãè©ä¾¡ããããèãã¦ã¿ã¾ããã.
main = undefined >> print "hello"
ãã®ã³ã¼ããå®è¡ããã¨, "hello"ã¨è¡¨ç¤ºãããã¨ç¡ãundefined ã®ä¾å¤ãé£ã¶ãã§ããã.
ãããå³ã«æãã¨æ¬¡ã®ããã«ãªãã¾ã.
undefined ã®ç®±ãéããã¨, ä¾å¤ãé£ãã§ãã®ä»ã®ã³ã¼ããè©ä¾¡ãããã¨ç¡ã, ããã°ã©ã ã¯çµäºãã¾ã.
å³ã«æãã¨, >> ã®ç¬¬ä¸å¼æ°ãè©ä¾¡ããç¬éçµäºã, print "hello" ãè©ä¾¡ãããªãã¨ããã®ãããåããã¾ã.
éã«, undefined ã®ç®±ãå¤ããªããã°, ä¾å¤ã¯é£ã¶ãã¨ç¡ãããã°ã©ã ã¯ãã¡ãã¨åä½ãã¾ã.
main = let x = undefined : x in print (null x)
å³ã«æãã¨, ãããªãã¾ã.
ä¸ã®çµµãè¦ã¦åããããã«, null x ã§ã¯ undefined ã¯è©ä¾¡ãããªããã§ãã (undefinedãå²ã£ã¦ããåè§ãå¤ããªã).
ã ããä¾å¤ãé£ã°ãªãã£ããã§ãã.
åè§ = thunk
ä¸ã®å³ã§åè§ã«æ¸ãããã®ã¯, thunk ã¨å¼ã°ãããã®ã§ã.
å¾ã§è©ä¾¡ãã, ãã©ãã¯ããã¯ã¹ã®ãããªãã®ã§ã.
ãããè©ä¾¡ãããä½ãåºã¦ãããã¯, è©ä¾¡ããªããã°åããã¾ãã.
çµµã®ä¸ã§ã¯, thunk ãè©ä¾¡ããã¨, ã©ãã©ãç®±ãåãã¦ããã®ã§ã.
ããã, ç®±ã¯ã©ãã¾ã§ãã¨ãããã§ã¯ããã¾ãã.
ããå
¨ã¦ã®ç®±ãåããªããã°ãããªããªãã°, null (undefined : x) ã®å¼æ°ãå
¨ã¦è©ä¾¡ãããã¨ãã¦, ç¡éã«ã¼ãã«ãªã£ã¦ãã¾ãã¯ãã§ã.
null ã®åå²ã¯, ãã¼ã¿æ§æå (:) ã®ãã¿ã¼ã³ãããã§è¡ããã¾ã.
ãã®åä½ããæ¨æ¸¬ããã«, ãã¼ã¿æ§æåã®ç®±ãã¨ããæã«, åãæ¢ããã¯ããã§è©ä¾¡ãæ¢ã¾ãã®ã§ã.
JavaScriptã§æ¸ãã¦ã¿ã
以ä¸ã®ãã¨ãè¸ã¾ãã¦, JavaScriptã§é
延è©ä¾¡ãå®è£
ãã¦ã¿ã¾ã.
ã¾ãã¯, åºæ¬çãªãã¼ã¿ã§ã.
thunk ã¯, å¤ãä¿æãã¦ããã¦å¾ã§è©ä¾¡ãããããªç®±ã§ã.
function Thunk (value) { this.value = value; }
使ãæ¹ã¯
> x = new Thunk(10);
Thunk
> x.value;
10
ã§ã¯ãªãã¦,
> x = new Thunk(function () { return 10; }); Thunk > x.value; function () { return 10; } > x.value(); 10
ã§ã.
ãããããã¨ã§, Haskell ã®
x = y y = 20
ã¯,
> x = new Thunk(function () { return y; }); Thunk > y = new Thunk(function () { return 20; }); Thunk > x.value(); Thunk > x.value().value(); 20
ã®ããã«æ¸ãã¾ã.
value ãä½åº¦ãè©ä¾¡ãããã¨ã§, å¤ãå¾ããã¨ãã§ãã¾ã.
λ㮠wrapper ã¨, thunk ãäºã¤åã£ã¦é¢æ°é©ç¨ãããã®ãä½ã App ãæ¸ãã¾ã.
function Lambda (fn) { this.fn = fn; } function App (fn, arg) { this.fn = fn; this.arg = arg; }
次ã«, thunk ãè©ä¾¡ããé¢æ°ã§ã.
thunk ã§ããéãã¯ç®±ãå¤ãç¶ãã¾ã.
function Evaluate (val) { while (val instanceof Thunk) { val = val.value(); if (val instanceof App) { val = (PeelLambda(Evaluate(val.fn)))(val.arg); } } return val; } function PeelLambda (lam) { if (!(lam instanceof Lambda)) { throw "type error: apply a non-lambda to a value" } return lam.fn; }
ããã§,
val = (PeelLambda(Evaluate(val.fn)))(Evaluate(val.arg));
ã§ã¯ãªããã¨ã«æ³¨æãã¦ä¸ãã.
å¤ã¯è©ä¾¡ããã«, thunk ã®ã¾ã¾é¢æ°ã«é©ç¨ããã®ã§ãï¼ï¼ï¼
äºã¤ã® thunk ããé¢æ°é©ç¨ã® thunk ãä½ããã®ãæºåãã¦ããã¾ã.
å
ã»ã©ã® App ã¯, ç´æ¥ä½¿ãã¨å
¨ä½ã thunk ã§å
ã¾ãªãã®ã§, 代ããã«ãã¡ãã® Apply ã使ããã¨ã«ãã¾ã.
function Apply (fn) { return function (arg) { return new Thunk(function () { return new App(fn, arg); }); }; }
ãã, æºåã¯æ´ãã¾ãã.
Thunk, Apply, Lambda ãå®éã«ä½¿ã£ã¦å®è£
ãã¦ã¿ã¾ããã.
ç®æãã¯, fib = 0 : 1 : zipWith (+) fib (tail fib) ãJavaScript ã§å®è£
ãããã¨ã§ãï¼
ãããå®è£
ã§ããã, é
延è©ä¾¡ã®å®è£
ããã³ãã¢ã³ã§ãããï¼
JavaScript ã®ããããå¤ã¯, thunk ã§å ã¾ãã¾ã.
> twenty = new Thunk(function () { return 20; }); Thunk > twenty.value; function () { return 20; } > Evaluate(twenty); 20 > x = new Thunk(function () { return y; }); Thunk > y = new Thunk(function () { return 20; }); Thunk > Evaluate(x); 20
é¢æ°ã¯ new Lambda ã使ã£ã¦, 次ã®ããã«æ¸ãã¾ã.
var add = new Lambda(function (x) { return new Lambda(function (y) { return new Thunk(function () { return Evaluate(x) + Evaluate(y); }); }); }); var sub = new Lambda(function (x) { return new Lambda(function (y) { return new Thunk(function () { return Evaluate(x) - Evaluate(y); }); }); });
ãããç¨ã㦠1 + 2 ãè¨ç®ãã¦ã¿ã¾ã.
> one = new Thunk(function () { return 1; }); Thunk > two = new Thunk(function () { return 2; }); Thunk > onetwo = new Thunk(function () { return Apply(Apply(add)(one))(two); }); Thunk > Evaluate(onetwo); 3
ã¯ã, 1 + 2 = 3 ã¨ãããã¨ãåããã¾ãã.
é¢æ°é©ç¨ããããããæã« Apply ã使ãã¾ã.
ãªãã«ã¼ãªã¼åãããã©ã«ããªã®ã, ããã§ãåããã ã¨æãã¾ã.
ã«ã¼ãªã¼åãã¦ãæ¹ãçµ±ä¸çã«æ±ããã§ãããï¼
ãªã¹ããå®è£ ããã¨, ãããªæãã§ã.
function Cons (car, cdr) { this.car = car; this.cdr = cdr; } function Nil () { } // [] var nil = new Thunk(function () { return new Nil(); }); // (:) var cons = new Lambda(function (x) { return new Lambda(function (xs) { return new Thunk(function () { return new Cons(x, xs); }); }); });
JavaScript ã®ãã¼ã¿ã¨ã㦠new Nil, new Cons ã使ããã¨ã¯ã§ããã®ã§ãã, ãã㯠nil, cons ãéãã¦ä½¿ããªãã¦ã¯ãªãã¾ãã.
ä½æ
ãªã, é©å½ã« new Cons... ã¨ãæ¸ãã¨, thunk ã§å
ãã®ãå¿ããããã§ã.
Evaluate é¢æ°ã§, ãªã¹ããå¦çããæã«ã©ããªãã, èãã¦ã¿ã¾ã.
> zero = new Thunk(function () { return 0; }); Thunk > // let x = 0 : x > x = new Thunk(function () { return new Cons(zero, x); }); Thunk
è©ä¾¡ãã¾ã.
> Evaluate(x); Cons
ç¡éã«ã¼ãã«ãªãã¾ããï¼
ããã¯, Cons ã¨ãããã¼ã¿æ§æå㧠Evaluate ãæ¢ã¾ãããã§ã.
å®è£
ãé²ãã¾ããã.
mapé¢æ°, takeé¢æ°ã¯æ¬¡ã®ããã«ãªãã¾ã.
// map _ [] = [] // map f (x:xs) = f x : map f xs var map = new Lambda(function (f) { return new Lambda(function (list) { return new Thunk(function () { var xxs = Evaluate(list); if (xxs instanceof Cons) { var x = xxs.car; var xs = xxs.cdr; return Apply(Apply(cons)(Apply(f)(x))) (Apply(Apply(map)(f))(xs)); } else { return nil; } }); }); }); // take _ [] = [] // take n _ | n <= 0 = [] // take n (x:xs) = x : take (n - 1) xs var take = new Lambda(function (n) { return new Lambda(function (list) { return new Thunk(function () { var xxs = Evaluate(list); if (xxs instanceof Cons) { var nval = Evaluate(n); if (nval <= 0) { return nil; } else { var x = xxs.car; var xs = xxs.cdr; return Apply(Apply(cons)(x)) (Apply(Apply(take)(Apply(Apply(sub)(n))(one)))(xs)); } } else { return nil; } }); }); });
Apply ããã£ã±ãã§ãã.
é¢æ°é©ç¨ããããããæã«, Apply ã使ããªããã°ããã¾ãã.
ããã«, æ¡ä»¶åå²ããæ㧠Evaluate ã使ã£ã¦ãããã¨ã«æ³¨æãã¦ä¸ãã.
() ã¨, monad çãªé¢æ°ãç¨æãã¦ããã¾ã.
function Unit () { } // () var unit = new Thunk(function () { return new Unit(); }); // print = \x -> log x; return () var print = new Lambda(function (x) { return new Thunk(function () { console.log(Evaluate(x)); return Apply(return_)(unit); }); }); // return var return_ = new Lambda(function (x) { return new Thunk(function () { return x; }); }); // (>>) var then = new Lambda(function (fn1) { return new Lambda(function (fn2) { return new Thunk(function () { Evaluate(fn1); Evaluate(fn2); }); }); });
ã¾ãã¶ã£ã¡ãã, ããã®ã³ã¼ãã¯ãã¾ã monad çãããªãã¦, åãæ¢ããåããããªã³ã¼ãã§ã.
ãã¡ãã¨ããã³ã¼ãã¯èªåã§æ¸ãã¦ã¿ã¦ä¸ãã.
ãã¨, ããã§ã® print é¢æ°ã¯ Haskell ã§è¨ã print é¢æ°ã¨åä½ãç°ãªãã®ã§, 注æãã¦ä¸ãã.
map é¢æ°ãçä¼¼ãã¦, mapM_ ãæ¸ãã¦ã¿ã¾ã.
// mapM_ _ [] = return () // mapM_ f (x:xs) = f x >> mapM_ f xs var mapM_ = new Lambda(function (f) { return new Lambda(function (list) { return new Thunk(function () { var xxs = Evaluate(list); if (xxs instanceof Cons) { var x = xxs.car; var xs = xxs.cdr; return Apply(Apply(then)(Apply(f)(x))) (Apply(Apply(mapM_)(f))(xs)); } else { return Apply(return_)(unit); } }); }); });
以ä¸ã®ç¨æã§, Haskell ã®
inf = 0 : map (+1) inf
ã¯æ¬¡ã®ããã«ãªãã¾ã.
var zero = new Thunk(function () { return 0; }); var one = new Thunk(function () { return 1; }); // inf = 0 : map (+1) inf var inf = new Thunk(function () { return Apply(Apply(cons)(zero)) (Apply(Apply(map)(Apply(add)(one)))(inf)); });
å®è¡ããã¨æ¬¡ã®ããã«ãªãã¾ã.
> twenty = new Thunk(function () { return 20; }); Thunk > // mapM_ print (take 20 inf); > Evaluate(Apply(Apply(mapM_)(print))(Apply(Apply(take)(twenty))(inf))); 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
ãã¾ãåãã¦ããããã«è¦ãã¾ãâ©(ï¼◡ï¼*)â©
ideone ã§ã®å®è¡çµæãç½®ãã¦ããã¾ã: http://ideone.com/KXT74d .
ãããããã£ããããæ°ãæ¸ããããªã£ã¦æ¥ã¾ãããã.
ã¦ãºã¦ãºãã¦ããã¨æãã¾ã.
fib = 0 : 1 : zipWith (+) fib (tail fib)
ãããå®è£
ããã«ã¯, zipWith 㨠tail é¢æ°ãå¿
è¦ã§ã.
zipWith ã¯äºã¤ã®ãªã¹ããé¢æ°ã§è²¼ããããã¦æ°ãããªã¹ããä½ãé¢æ°ã§ã.
tail ã¯, ãªã¹ãã®é 以å¤ãè¿ãé¢æ° function tail(list) { return list.slice(1); }(大ä½ãããªæã; ãã³ãã¯ç©ºãªã¹ããªãã¨ã©ã¼ãé£ã¶) ã§ãã.
// zipWith f (a:as) (b:bs) = f a b : zipWith f as bs // zipWith _ _ _ = [] var zipWith = new Lambda(function (f) { return new Lambda(function (listx) { return new Lambda(function (listy) { return new Thunk(function () { var xxs = Evaluate(listx); if (xxs instanceof Cons) { var yys = Evaluate(listy); if (yys instanceof Cons) { return Apply(Apply(cons)(Apply(Apply(f)(xxs.car))(yys.car))) (Apply(Apply(Apply(zipWith)(f))(xxs.cdr))(yys.cdr)); } } else { return nil; } }); }); }); }); // tail [] = error "tail: empty list" // tail (_:xs) = xs var tail = new Lambda(function (list) { return new Thunk(function () { var xxs = Evaluate(list); if (xxs instanceof Cons) { return xxs.cdr; } else { throw "tail: empty list"; } }); });
ãã£ããããæ°ã®ç¡éåã¯, 次ã®ããã«å®è£ ã§ãã¾ã.
// fib = 0 : 1 : zipWith (+) fib (tail fib) var fib = new Thunk(function () { return Apply(Apply(cons)(zero)) (Apply(Apply(cons)(one)) (Apply(Apply(Apply(zipWith)(add))(fib))(Apply(tail)(fib)))); }); var twenty = new Thunk(function () { return 20; }); Evaluate(Apply(Apply(mapM_)(print))(Apply(Apply(take)(twenty))(fib)));
å®è¡ããã¨
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181
ã¨ãªãã¾ã. (ideone: http://ideone.com/6HJhqA )
ãã³ã¶ã¤ã§ãï¼ JavaScript ã§ãã£ããããæ°ã®ç¡éãªã¹ããå®è£
ãããã¨ãã§ãã¾ããâ©(ï¼◡ï¼*)â©♡
æã®éã®åã³, ãã£ããããæ°ãå帰ççºãã¦ãããã¨ã«æ°ãä»ãã
ããããªãã, ä¸ã®å®è£
ã«ã¯åé¡ãããã¾ã.
ãã£ããããæ°ã®è¨ç®ã, å帰ççºãèµ·ããã¦ãã¾ã.
試ãã« add é¢æ°ã§è¶³ãç®ãå®è¡ãããåæ°ãã«ã¦ã³ããã¦ã¿ã¾ããã.
i = 0; var add = new Lambda(function (x) { return new Lambda(function (y) { return new Thunk(function () { i++; return Evaluate(x) + Evaluate(y); }); }); });
> i = 0; 0 > Evaluate(Apply(Apply(mapM_)(print))(Apply(Apply(take)(twenty))(fib))); 0 1 1 ... 2584 4181 > i; 17690
ãã¹ã...
ãã£ããããæ°20åã§ãã®ã§, 大ä½è¶³ãç®ã¯20åããã°ããã¯ãã§ã.
é©å½ã«
> i = 0; 0 > twentyfive = new Thunk(function () { return 25; }); Thunk > Evaluate(Apply(Apply(mapM_)(print))(Apply(Apply(take)(twentyfive))(fib))); 0 1 ... 6765 10946 17711 28657 46368 > i; 196392
ãã¼ã¼ãã¼ã¼ã®ã¼ã¼ãã¼ã¼ãã¼ã¼ãã£æéããããã¾ã...
ä½ãæªããã§ãããã.
å
ã»ã©ã® fib ããæåã®3ã¤ãè©ä¾¡ããã¾ã§ã®æ§åã, å³ã«æãã¦ã¿ã¾ãã.
mapM_ print fib ããã¨èãã¦ä¸ãã.
æåããä¸è¡ã§, ã0ãã1ãã表示ããã¾ã.
ãã®å¾, 3ã¤ç®ã®ã1ãã®è¡¨ç¤ºã®ããã«, fib ãå®ç¾©ã¾ã§æ»ã£ã¦ã¾ã thunk ãéããã¨ã2åãã¦ãã¾ã.
ããã§ã, fib ãå¼ã¶ãã³ã«, å®ç¾©ã¾ã§æ»ã£ã¦ãããããã¡ãªãã§ã.
ãã®å¾ã«, fib ã®4ã¤ç®ãè¨ç®ããããã«å®ç¾©ã¾ã§æ»ã£ã¦ãã¦ã¯, ãã£ãã3ã¤ç®ãåãã£ã¦ããã®ã«å¿ä½ãªãã§ã.
fib ã®ç®±ãå¹¾ã¤ãå¤ããã, ããã¾ã§ã®å¦çã¯ä½åº¦ãããªãã¦ããã®ã§ã¯ãªãã§ãããã.
ããåã®çµæãå¼ã¶ããã«ãã¦, 3ã¤ã¾ã§ã®å¤ãè©ä¾¡ããã®ã次ã®å³ã§ã.
ãã¡ãã®æ¹ãããã«3ã¤ã®è¦ç´ ãåãåºãã¾ãã.
ããã ãã§ãªã, ã(+) 0 1ããå®è¡ãã, fib !! 2 ãæ°åã«æ±ºå®ãã¦ãã¾ãã®ã§, ãã以éã®ã¹ããã㧠fib ãå¼ã¶æã¯ã0 : 1 : 1 : zipWith ...ãã¨ãªãã¾ã.
3ã¤ç®ãè¨ç®ããããã®è¶³ãç®(+)ãä¸è¦ã«ãªãã®ã§ã.
åé¡ãåãã£ãæã§, å®è£
ãå¤æ´ãã¾ã.
è©ä¾¡ããã¨ããã¾ã§ãã£ãã·ã¥ããããã«, Evaluate é¢æ°ã ãå¤æ´ãã¾ã.
function Evaluate (val) { while (val instanceof Thunk) { var v = val; if (v.evaluated) { val = val.value; } else { val = val.value(); } if (val instanceof App) { val = (PeelLambda(Evaluate(val.fn)))(val.arg); } v.evaluated = true; v.value = val; } return val; }
å®è¡ãã¾ã.
> i = 0; 0 > Evaluate(Apply(Apply(mapM_)(print))(Apply(Apply(take)(twenty))(fib))); 0 1 1 ... 4181 > i; 18
ï½·ï¾ââââ✧*ãã¾(๑ï¼◡ï¼๑)ï¾ï¾✧*ãââââ!!
> i = 0; 0 > hundred = new Thunk(function () { return 100; }); Thunk > Evaluate(Apply(Apply(mapM_)(print))(Apply(Apply(take)(hundred))(fib))); 0 1 1 2 3 5 8 ..... 31940434634990100000 51680708854858330000 83621143489848430000 135301852344706760000 218922995834555200000 > i; 98
ãã£ãã¯æ»
è¶è¦è¶æéãããã£ã¦ãã®ã«, ä»åº¦ã¯100åãä½è£ã§æ±ããããããã«ãªãã¾ããï¼(ideone: http://ideone.com/ILSuJW )
足ãç®ã®åæ°ã, åã£ã¦ã¾ãï¼ (fib ãã100åæ±ããã®ã«, æåã®äºã¤ã¯è¶³ãç®ãããªãã§ãåãã£ã¦ããã®ã§, 100 - 2 = 98 ãªã®ã§ãã, ã80ãã¨åºã人ã¯, çç±ãèãã¦ã¿ã¦ä¸ãã.)
ãã£ã Evaluate ã ãã®å¤æ´ã§, ãã¾ãåãããã«ãªãã®ã¯, ã¨ã£ã¦ãå¬ãããªã£ã¦.
ä¸ã®æ¹ã®æ¡ããã¾ãæ±ãããã¦ãªãã®ã¯, JavaScriptã®æ°å¤ã®æ±ãã®ãããªã®ã§, ä»æ¹ãªãã§ãã.
Evaluate é¢æ°ã, ä½å¦ã¾ã§å¦çãããã¯, ã¨ã¦ãéè¦ã§ã.
ä½åº¦ãè¨ã£ã¦ãã¾ãã, ãã¼ã¿æ§æåãç¾ããã, ããã§ã¹ããããã¾ã.
ããä¸ã¤, ä»ã¾ã§è¨ã£ã¦ãªãã£ãã®ã, λã§ã.
ã»ã, while (val instanceof Thunk) {... ã¨ããã³ã¼ãã§ãã®ã§, new Lambda ã«å¯¾ãã¦ã¯å¦çãã¾ãã.
ããã¯ã¨ã¦ãéè¦ãªè¦³å¯ã§, WHNF ã¨ããã®ã§ãã, ãã®è¨äºãæ´ã«é·ããªããããªã®ã§ååãåºãã ãã«ã¨ã©ãã¾ã.
é
延è©ä¾¡ã¯ã©ãåãã¦ããã, ãåããããã ãããã¨æãã¾ã.
ãã¼ã¯ã¼ãã¯, thunk ã§ã.
å³ããã£ã±ãæãã¦ã©ããããµãã« thunk ã®ç®±ãå¤ãã¦ããã, èãã¦ã¿ã¦ä¸ãã.
JavaScript == Haskell
ããä¸å, fib ã®ã³ã¼ããè¦ã¦ã¿ã¾ã.
var fib = new Thunk(function () { return Apply(Apply(cons)(zero)) (Apply(Apply(cons)(one)) (Apply(Apply(Apply(zipWith)(add))(fib))(Apply(tail)(fib)))); });
Haskellã®ã³ã¼ãã¯ããã§ãã.
fib = 0 : 1 : zipWith (+) fib (tail fib)
ã¤ã¾ã,
fib = ((:) (0)) (((:) (1)) (((zipWith (+)) (fib)) (tail (fib))))
ã§ãã, æ´ã«é¢æ°é©ç¨ã«å ¨ã¦($)ãç¨ããã¨
fib = ($) (($) (:) 0) (($) (($) (:) 1) (($) (($) (($) zipWith (+)) fib) (($) tail fib)))
ã¨ãªãã¾ã.
ãã... ããã£ã¦JavaScript ã®ã³ã¼ãã¨($)ã®ä½ç½®ã¨Applyã®ä½ç½®ã, ãã®ã¾ã¾ãããªãã§ããï¼
ã¨è¨ããã¨ã¯...
$ = Apply
ã¾ããã®...
var fib = new Thunk(function () { return ($)(($)(cons)(zero)) (($)(($)(cons)(one)) (($)(($)(($)(zipWith)(add))(fib))(($)(tail)(fib)))); });
ããã... ããã¯... Haskell ã®ã³ã¼ãã§ãï¼ï¼ï¼
add = (+) cons = (:) zero = 0 one = 1 fib = ($)(($)(cons)(zero)) (($)(($)(cons)(one)) (($)(($)(($)(zipWith)(add))(fib))(($)(tail)(fib))));
ãããããããããã...
JavaScript 㨠Haskell ã¯ä¸ç·ã ã£ãã®ã ... +ã:.ï¾٩(๑>◡<๑)۶:.。+ï¾
ã¾ã¨ã
thunk ã®ã¤ã¡ã¼ã¸ãæããããã§ãããã.
çµµãæãã¦è¦ããã¨ãéè¦ã§ã.
ç§ã, ãã£ã±ãç®±ãæãã¾ãã.
詳ãããã¨ã¯, Haskell Wiki ã® Thunk - HaskellWiki, Lazy evaluation - HaskellWiki, Weak head normal form - HaskellWiki, ãã㦠Haskell/Laziness - Wikibooks, open books for an open world ããããèªãã§åå¼·ãã¦ä¸ãã.
ããã¦ä½ããã, é
延è©ä¾¡ããªãè¨èªã§é
延è©ä¾¡ãå®è£
ãã¦ã¿ãã®ãä¸çªç解ãæ·±ãã¾ã.
ã好ããªè¨èªã§, é
延è©ä¾¡ãå®è£
ãã¦ã¿ã¦ä¸ãã.
è£è©±
ãã®ããã°è¨äºãæ¸ãããã£ããã¯, fay(https://github.com/faylang/fay)ã§ãã.
Haskell ã®ã³ã¼ãã JavaScript ã®ã³ã¼ãã«å¤æããããã°ã©ã ã§ã.
ãããã©ãå®è£
ãã¦ããã®ã, æåã¯è¦å½ãä»ãã¾ããã§ãã.
ç§ã¯ã¾ã, fib ã Haskell ã§å®è£
, fay ã§å¤æã, ãã®åºåã³ã¼ããèªã¿ã»ã©ãã¦ã¿ãã®ã§ã.
ããã¦, thunk ãã©ãå®è£
ããã°ããã, ãããã©ãè©ä¾¡ããã°ããããåãã£ãã®ã§ã.
thunk, WHNF ã«ã¤ãã¦èª¿ã¹, å¾ã
ã«ç解ãã¦ããç§ã¯, fay ã®åºåã³ã¼ããåèã«ããªãã JavaScript ã§æ¸ãã¦ã¿ã¾ãã.
é«éé¢æ°ã°ããã§ãããã°ãã«ããç¶æ³ã§, åã㦠mapM_ print (take 20 fib) ããã¾ãåããæã¯, å¿ãéãã¾ãã.
ãã®æåã«, å帰ççºãã¦ãããã¨ã«æ°ãä»ãã¾ããã§ãã.
æ°æ¥ãã¦, ãã£ããããæ°ã100åæ±ãããã¨æã£ãã®ã§ã.
ãã®æ, åãã¦å帰ççºãã¦ãããã¨ã«æ°ãä»ãã¾ãã.
fay ã§åºåããã³ã¼ãã§ã¯, ããã«ãã£ããããæ°100åãè©ä¾¡åºæ¥ã¾ãã.
æåã¯åå ããåããã¾ããã§ãã.
ã³ã¼ã㯠thunk ã°ã£ããã§, é常ã«ãããã°ãã«ãããã®ã§ãã.
ãã£ãã·ã¥ãã¦ããªãããã ã¨åãã£ãã®ã¯, fay ã®åºåã³ã¼ããèªã¿ç´ããæã§ãã.
ããã¯, å帰ççºã«æ°ãã¤ããæ°æ¥å¾, ããã¦ãã®è¨äºãæ¸ããåæ¥ã§ãã.
ã³ã¼ãå ¨ä½
ã³ãããã¦å®è¡ããã人ã®ããã«å
¨ä½ã®ã³ã¼ãç½®ãã¦ããã¾ãã♡-(╹ã®ï¼✿)
以ä¸ã®ã³ã¼ãã®å®è¡çµæã¯ãã¡ãã§ã: http://ideone.com/5FmJha .
ã¨ãããã, èªåã§å®è£
ããããä¸ãã♡-(╹ã®<â
)
function Thunk (value) { this.value = value; } function Lambda (fn) { this.fn = fn; } function App (fn, arg) { this.fn = fn; this.arg = arg; } function Evaluate (val) { while (val instanceof Thunk) { var v = val; if (v.evaluated) { val = val.value; } else { val = val.value(); } if (val instanceof App) { val = (PeelLambda(Evaluate(val.fn)))(val.arg); } v.evaluated = true; v.value = val; } return val; } function PeelLambda (lam) { if (!(lam instanceof Lambda)) { throw "type error: apply a non-lambda to a value" } return lam.fn; } function Apply (fn) { return function (arg) { return new Thunk(function () { return new App(fn, arg); }); }; } // add = (+) var add = new Lambda(function (x) { return new Lambda(function (y) { return new Thunk(function () { return Evaluate(x) + Evaluate(y); }); }); }); // sub = (-) var sub = new Lambda(function (x) { return new Lambda(function (y) { return new Thunk(function () { return Evaluate(x) - Evaluate(y); }); }); }); function Cons (car, cdr) { this.car = car; this.cdr = cdr; } function Nil () { } // [] var nil = new Thunk(function () { return new Nil(); }); // (:) var cons = new Lambda(function (x) { return new Lambda(function (xs) { return new Thunk(function () { return new Cons(x, xs); }); }); }); // head [] = error "head: empty list" // head (x:_) = x var head = new Lambda(function (list) { return new Thunk(function () { var xxs = Evaluate(list); if (xxs instanceof Cons) { return xxs.car; } else { throw "head: empty list"; } }); }); // tail [] = error "tail: empty list" // tail (_:xs) = xs var tail = new Lambda(function (list) { return new Thunk(function () { var xxs = Evaluate(list); if (xxs instanceof Cons) { return xxs.cdr; } else { throw "tail: empty list"; } }); }); // map _ [] = [] // map f (x:xs) = f x : map f xs var map = new Lambda(function (f) { return new Lambda(function (list) { return new Thunk(function () { var xxs = Evaluate(list); if (xxs instanceof Cons) { var x = xxs.car; var xs = xxs.cdr; return Apply(Apply(cons)(Apply(f)(x))) (Apply(Apply(map)(f))(xs)); } else { return nil; } }); }); }); // take _ [] = [] // take n _ | n <= 0 = [] // take n (x:xs) = x : take (n - 1) xs var take = new Lambda(function (n) { return new Lambda(function (list) { return new Thunk(function () { var xxs = Evaluate(list); if (xxs instanceof Cons) { var nval = Evaluate(n); if (nval <= 0) { return nil; } else { var x = xxs.car; var xs = xxs.cdr; return Apply(Apply(cons)(x)) (Apply(Apply(take)(Apply(Apply(sub)(n))(one)))(xs)); } } else { return nil; } }); }); }); function Unit () { } // unit = () var unit = new Thunk(function () { return new Unit(); }); // print = \x -> log x; return () // (not so monadic...) var print = new Lambda(function (x) { return new Thunk(function () { console.log(Evaluate(x)); return Apply(return_)(unit); }); }); // return var return_ = new Lambda(function (x) { return new Thunk(function () { return x; }); }); // (>>) var then = new Lambda(function (fn1) { return new Lambda(function (fn2) { return new Thunk(function () { Evaluate(fn1); Evaluate(fn2); }); }); }); // mapM_ _ [] = return () // mapM_ f (x:xs) = f x >> mapM_ f xs var mapM_ = new Lambda(function (f) { return new Lambda(function (list) { return new Thunk(function () { var xxs = Evaluate(list); if (xxs instanceof Cons) { var x = xxs.car; var xs = xxs.cdr; return Apply(Apply(then)(Apply(f)(x))) (Apply(Apply(mapM_)(f))(xs)); } else { return Apply(return_)(unit); } }); }); }); // zipWith f (a:as) (b:bs) = f a b : zipWith f as bs // zipWith _ _ _ = [] var zipWith = new Lambda(function (f) { return new Lambda(function (listx) { return new Lambda(function (listy) { return new Thunk(function () { var xxs = Evaluate(listx); if (xxs instanceof Cons) { var yys = Evaluate(listy); if (yys instanceof Cons) { return Apply(Apply(cons)(Apply(Apply(f)(xxs.car))(yys.car))) (Apply(Apply(Apply(zipWith)(f))(xxs.cdr))(yys.cdr)); } } else { return nil; } }); }); }); }); var zero = new Thunk(function () { return 0; }); var one = new Thunk(function () { return 1; }); var twenty = new Thunk(function () { return 20; }); var hundred = new Thunk(function () { return 100; }); // inf = 0 : map (+1) inf var inf = new Thunk(function () { return Apply(Apply(cons)(zero)) (Apply(Apply(map)(Apply(add)(one)))(inf)); }); // fib = 0 : 1 : zipWith (+) fib (tail fib) var fib = new Thunk(function () { return Apply(Apply(cons)(zero)) (Apply(Apply(cons)(one)) (Apply(Apply(Apply(zipWith)(add))(fib))(Apply(tail)(fib)))); }); // main = mapM_ print (take 100 fib) var main = new Thunk(function () { return Apply(Apply(mapM_)(print))(Apply(Apply(take)(hundred))(fib)); }); Evaluate(main);