【问题标题】:Understanding lazy lists in Ocaml了解 Ocaml 中的惰性列表
【发布时间】:2020-05-11 21:31:46
【问题描述】:

我的目标是通过获取两个流,将它们压缩在一起,颠倒顺序并应用我的差异函数来制作三重而不是双重来理解这些流。

例如,将此函数应用于赔率流 (1,3,5,7...) 和偶数流 (0,2,4,6,8) 将产生 [(0,1 ,-1); (2,3,-1); (4,5,-1)] 等等,但它应该适用于任何流,而不仅仅是赔率和偶数 - 即三元组中的第三个数字并不总是“-1”。

    type 'x str = Cons of 'x * ('x strm) | Nil
    and  'x strm = unit -> 'x str

    let diff :  int -> int -> int =  fun x y -> x - y

    let rec flip_diff : 'x stream -> 'y stream -> ('x * 'y -> 'z) -> ('y * 'x * 'z) stream =
      fun x y f ->  fun () ->Cons((head y) (head x) (f y x), flip_diff (tail y) (tail x))

我的错误信息(与打字有关)是这样的:

# let rec flip_diff : 'x stream -> 'y stream -> ('x * 'y -> 'z) -> ('y * 'x * 'z) stream =
        fun x y f ->  fun () ->Cons((head y) (head x) (f y x), flip_diff (tail y) (tail x));;
Error: This expression has type
         ('x -> 'a -> 'b) stream = unit -> ('x -> 'a -> 'b) str
       but an expression was expected of type 'x * ('x -> 'a -> 'b)

老实说,我很难把我的头绕在打字上。使用惰性流处理较小的函数很容易,但分段构建函数然后将其放在 Ocaml 中就更难了。

【问题讨论】:

    标签: ocaml


    【解决方案1】:

    键入只是在运行时错误发生之前对其进行处理。类型检查器对您说的是,这个表达式的使用就像它在一个地方是一个函数流('x -> 'a -> 'b) stream,在另一个地方作为一对'x * ('x -> 'a -> 'b)。由于同一个对象不能是一对和一个函数(流是您的表示中的一个函数),因此编译器会在此处停止并要求您修复您的代码,这将在运行时(在具有动态类型的语言中)使您的程序崩溃.

    错误消息还包含一些指针,可让您识别This expression 的含义。您没有提供它们,因此很难猜测编译器的具体表达方式。

    但我可以试试,首先,让我们仔细看看下面的表达式:

    Cons((head y) (head x) (f y x), flip_diff (tail y) (tail x))
    

    让我们选择Cons 对的第一个组成部分,即(head y) (head x) (f y x)。您应该已经知道,OCaml 中的函数仅通过并置调用,因此f p q 表示使用xy 参数调用f。这里f(head y)p(head x)qf y x。所以编译器推断,y 应该是一个接受两个参数的函数流,第一个流的元素xf x y 的应用结果xy 是流。所以f 应该是一个接受两个流的函数,但是您的注释说它是一个应用于一对的函数。已经有问题了。提示:您的意思可能是 f (head y, head x) 如您所愿(如果我们将您自己的类型注释视为您的愿望)将 f 相应地应用于由 yx 的元素组成的对。

    您的代码的另一个问题是您递归调用 flip_diff 时使用的参数比预期的少,例如 flip_diff (tail y) (tail x) 而正如您自己的注释所说,它接受三个参数、两个流和函数,例如,这就是你的意思flip_diff (tail y) (tail x) f(可能你真的不想在递归调用中翻转流)。

    【讨论】: