如何在SMLNJ中使用curried函数生成无限的斐波纳契数列表?

时间:2013-10-31 18:17:50

标签: sml smlnj

我编写了一个通用例程,它接受多个参数并生成一个无限的斐波纳契数列表,如下所示:

datatype 'a seq = Nil | Cons of 'a * (unit -> 'a seq) ;
fun fibo (a,b) = Cons(a, fn () => fibo(b,a+b));

val fib = fibo(0 , 1);

但问题是我想用currying技术从0和1开始生成这个无限的斐波纳契数列表,我对currying的概念感到非常困惑。

通过使用这个例子可以让我了解一下currying的概念吗?如何使用currying在SMLNJ中生成无限的斐波纳契数列表?

2 个答案:

答案 0 :(得分:3)

你走了:

datatype 'a seq = Nil | Cons of 'a * (unit -> 'a seq) ;
fun fibo a b = Cons(a, fn () => fibo b (a + b));

val fib = fibo 0 1;

另一个(非常有用的)咖喱功能:

(* take n seq returns the first n items in seq. Raises Subscript if there
   are too few items. *)
fun take 0 _            = []
  | take _ Nil          = raise Subscript
  | take n (Cons (a,f)) = a :: take (n - 1) (f ())

示例(在mosml解释器中,所以它可能与SML / NJ略有不同):

- take 10 fib;
> val it = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] : int list

只是为了炫耀一点点干扰的力量:

val firstTen = take 10

- firstTen fib;
> val it = [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] : int list

这里发生的事情是,我只给take一个论点。 take的类型为int -> 'a seq -> 'a list,所以通过给它int参数,我得到类型为'a seq -> 'a list的东西 - 即一个返回'a seq的10个项的函数你把它作为输入。

答案 1 :(得分:0)

你的定义有点不对,因为它混合了fibo的curry和uncurried形式。

如果我理解正确,那么在编码层面上没有什么可以启发你的。咖喱和未经证实的定义之间存在微小的句法差异。

- fun plus_uncurried (a, b) = a + b;
val plus_uncurried = fn : int * int -> int
- plus_uncurried (3,5);
val it = 8 : int
-  fun plus_curried a b = a + b;
val plus_curried = fn : int -> int -> int
- plus_curried 3 5;
val it = 8 : int
- val incr = plus_curried 1;
val incr = fn : int -> int
- incr 4;
val it = 5 : int

在概念层面,咖喱功能似乎有点棘手,至少在开始时是这样。我个人只是想到一个curried函数作为一个返回一个需要更多参数的函数。当你最后给出最后一个论点时,你会得到答案。

(我不确定你为什么用OCaml标记这个问题,但在OCaml currying中是函数的惯用形式。所以你马上就习惯了。)

您可能正在寻找比int -> int -> int seq类型的函数更复杂的东西。如果是这样,你需要更仔细地描述一下你在寻找什么。只要指明你要找的东西的类型可能会有很大的帮助。

<强>更新

fibo中没有比上面的例子更复杂的了,除了你有一个递归调用。如果您只是更改fibo的第一部分,就像plus_uncurried更改为plus_curried一样,您将处理定义部分。要处理呼叫部分,请更改递归呼叫,方法与将plus_uncurried的呼叫更改为plus_curried的呼叫相同。