F#メモ
プログラミングF#のメモ
- 末尾再帰
元の関数
let factorial x = let rec tailFactorial x acc = if x <= 1 then acc else tailFactorial (x-1) (acc * x) tailFactorial x 1
ルイパンコ結果
public static class Factorial { // // Static Methods // public static int factorial (int x) { return Factorial.tailFactorial@5 (x, 1); } internal static int tailFactorial@5 (int x, int acc) { while (x > 1) { int arg_0E_0 = x - 1; acc *= x; x = arg_0E_0; } return acc; } }
ほぼ例と同じですね。
末尾再帰がwhileに置き換えられています。
- 継続
つまり、スタック上に「残されているもの」を格納するのではなく、「残されていること」を関数として格納してしまうわけです。
???
スタック領域(再帰呼び出し)の代わりにヒープ領域(関数値)を使用するのです。
…?
なんて思いつつうんうん唸って
http://www.geocities.jp/m_hiroi/func/haskell38.html
のfib(n)辺りまで読んでなんとなく分かった気がした。
二分木の葉の数を求める関数を継続で。
本に載っていたのと同じようなスタイルでやってみる。
type BinTree<'T> = | Node of 'T * BinTree<'T> * BinTree<'T> | Empty type IStep<'T> = | Fin of int | Step of int * (int -> IStep<'T>) let count (tree : BinTree<'T>) = let rec cnt tree acc = match tree with | Empty -> acc(0) | Node (x, l, r) -> Step(1, fun a -> cnt l (fun b -> cnt r (fun c -> (acc (a + b + c))))) let steps = cnt tree (fun x -> Fin(x)) let rec proc step = match step with | Fin(s) -> s | Step(x, next) -> proc (next (x)) proc steps
ポイントは
Step(1, fun a -> cnt l (fun b -> cnt r (fun c -> (acc (a + b + c)))))
の部分?
1が自分自信の葉っぱの数
fun a -> cnt l ...
のaが左側の葉っぱの和
fun b -> cnt r ...
のbが右側の葉っぱの和
fun d -> ...
でdが今までの総和にそれぞれの和を加算
let tree = Node(1, Node(2, Node(3, Node(4, Node(5, Empty, Empty), Node(6, Empty, Empty)), Node(7, Empty, Empty)), Empty), Empty) count tree > val it : int = 7 count Empty val it : int = 0 count (Node(1, Node(2, Empty, Empty), Node(3, Empty, Empty))) val it : int = 3
最後のを展開して確認。
展開順はだいぶ適当で省略する。
count (Node(1, Node(2, Empty, Empty), Node(3, Empty, Empty))) cnt tree (fun x -> Fin(x)) (Node(1, Node(2, Empty, Empty), Node(3, Empty, Empty))) → Step(1, fun a -> cnt Node(2, Empty, Empty (fun b -> cnt Node(3, Empty, Empty (fun c -> (acc (a + b + c))))) → Step(1, Step(1, Step(1, fun c -> a + b + c)) → 3
頭に???浮かべている状況からは多少前進した気がする。
おまけのルイパンコ結果。
だいぶ長かったの関係ありそうな部分だけで属性とか色々削除。
public static class TreeCount { internal static TreeCount.IStep<b> cnt@12<a, b> (TreeCount.BinTree<a> tree, FSharpFunc<int, TreeCount.IStep<b>> acc) { if (tree is TreeCount.BinTree<a>.Node) { TreeCount.BinTree<a>.Node node = (TreeCount.BinTree<a>.Node)tree; TreeCount.BinTree<a> item = node.item3; TreeCount.BinTree<a> item2 = node.item2; return TreeCount.IStep<b>.NewStep (1, new TreeCount<b, a>.cnt@16-1 (acc, item, item2)); } return acc.Invoke (0); } public static int count<T> (TreeCount.BinTree<T> tree) { TreeCount.IStep<object> step = TreeCount.cnt@12<T, object> (tree, new TreeCount.steps@18 ()); return TreeCount.proc@20<object> (step); } internal static int proc@20<a> (TreeCount.IStep<a> step) { while (step is TreeCount.IStep<a>.Step) { TreeCount.IStep<a>.Step step2 = (TreeCount.IStep<a>.Step)step; int item = step2.item1; FSharpFunc<int, TreeCount.IStep<a>> item2 = step2.item2; step = item2.Invoke (item); } return ((TreeCount.IStep<a>.Fin)step).item; } // // Nested Types // public abstract class BinTree<T> : IEquatable<TreeCount.BinTree<T>>, IStructuralEquatable, IComparable<TreeCount.BinTree<T>>, IComparable, IStructuralComparable { public static class Tags { public const int Node = 0; public const int Empty = 1; } public class Node : TreeCount.BinTree<T> { [CompilationMapping (SourceConstructFlags.Field, 0, 0), DebuggerNonUserCode, CompilerGenerated] public T Item1 { [DebuggerNonUserCode, CompilerGenerated] get { return this.item1; } } public TreeCount.BinTree<T> Item2 { [DebuggerNonUserCode, CompilerGenerated] get { return this.item2; } } public TreeCount.BinTree<T> Item3 { [DebuggerNonUserCode, CompilerGenerated] get { return this.item3; } } internal Node (T item1, TreeCount.BinTree<T> item2, TreeCount.BinTree<T> item3) { this.item1 = item1; this.item2 = item2; this.item3 = item3; } } internal class _Empty : TreeCount.BinTree<T> { [DebuggerNonUserCode, CompilerGenerated] internal _Empty () { } } internal class Node@DebugTypeProxy { public T Item1 { [DebuggerNonUserCode, CompilerGenerated] get { return this._obj.item1; } } public TreeCount.BinTree<T> Item2 { [DebuggerNonUserCode, CompilerGenerated] get { return this._obj.item2; } } public TreeCount.BinTree<T> Item3 { [DebuggerNonUserCode, CompilerGenerated] get { return this._obj.item3; } } public Node@DebugTypeProxy (TreeCount.BinTree<T>.Node obj) { this._obj = obj; } } public int Tag { get { return (!(this is TreeCount.BinTree<T>._Empty)) ? 0 : 1; } } public bool IsNode { get { return this is TreeCount.BinTree<T>.Node; } } public static TreeCount.BinTree<T> Empty { get { return TreeCount.BinTree<T>._unique_Empty; } } public bool IsEmpty { get { return this is TreeCount.BinTree<T>._Empty; } } static BinTree () { // Note: this type is marked as 'beforefieldinit'. TreeCount.BinTree<T>._unique_Empty = new TreeCount.BinTree<T>._Empty (); } internal BinTree () { } public static TreeCount.BinTree<T> NewNode (T item1, TreeCount.BinTree<T> item2, TreeCount.BinTree<T> item3) { return new TreeCount.BinTree<T>.Node (item1, item2, item3); } } internal class cnt@16-1<b, a> : FSharpFunc<int, TreeCount.IStep<b>> { public FSharpFunc<int, TreeCount.IStep<b>> acc; public TreeCount.BinTree<a> r; public TreeCount.BinTree<a> l; internal cnt@16-1 (FSharpFunc<int, TreeCount.IStep<b>> acc, TreeCount.BinTree<a> r, TreeCount.BinTree<a> l) { this.acc = acc; this.r = r; this.l = l; } public override TreeCount.IStep<b> Invoke (int a) { return TreeCount.cnt@12<a, b> (this.l, new TreeCount<b, a>.cnt@16-2 (this.acc, this.r, a)); } } internal class cnt@16-2<b, a> : FSharpFunc<int, TreeCount.IStep<b>> { public FSharpFunc<int, TreeCount.IStep<b>> acc; public TreeCount.BinTree<a> r; public int a; internal cnt@16-2 (FSharpFunc<int, TreeCount.IStep<b>> acc, TreeCount.BinTree<a> r, int a) { this.acc = acc; this.r = r; this.a = a; } public override TreeCount.IStep<b> Invoke (int b) { return TreeCount.cnt@12<a, b> (this.r, new TreeCount<b>.cnt@16-3 (this.acc, this.a, b)); } } internal class cnt@16-3<b> : FSharpFunc<int, TreeCount.IStep<b>> { public FSharpFunc<int, TreeCount.IStep<b>> acc; public int a; public int b; internal cnt@16-3 (FSharpFunc<int, TreeCount.IStep<b>> acc, int a, int b) { this.acc = acc; this.a = a; this.b = b; } public override TreeCount.IStep<b> Invoke (int d) { return this.acc.Invoke (d + this.a + this.b); } } public abstract class IStep<T> { public static class Tags { public const int Fin = 0; public const int Step = 1; } public class Fin : TreeCount.IStep<T> { public int Item { get { return this.item; } } internal Fin (int item) { this.item = item; } } public class Step : TreeCount.IStep<T> { public int Item1 { get { return this.item1; } } public FSharpFunc<int, TreeCount.IStep<T>> Item2 { get { return this.item2; } } internal Step (int item1, FSharpFunc<int, TreeCount.IStep<T>> item2) { this.item1 = item1; this.item2 = item2; } } public int Tag { get { return (!(this is TreeCount.IStep<T>.Step)) ? 0 : 1; } } public bool IsFin { get { return this is TreeCount.IStep<T>.Fin; } } public bool IsStep { get { return this is TreeCount.IStep<T>.Step; } } internal IStep () { } public static TreeCount.IStep<T> NewFin (int item) { return new TreeCount.IStep<T>.Fin (item); } public static TreeCount.IStep<T> NewStep (int item1, FSharpFunc<int, TreeCount.IStep<T>> item2) { return new TreeCount.IStep<T>.Step (item1, item2); } } internal class steps@18 : FSharpFunc<int, TreeCount.IStep<object>> { internal steps@18 () { } public override TreeCount.IStep<object> Invoke (int x) { return TreeCount.IStep<object>.NewFin (x); } } }