【问题标题】:Converting this piece of code from Haskell to SML (catamorphism / fold)将这段代码从 Haskell 转换为 SML(catamorphism / fold)
【发布时间】:2020-08-15 05:46:57
【问题描述】:

我正在尝试将这段代码从 Haskell 转换为 SML,这将产生一个高阶函数(众所周知的 foldr)

type List_alg x u = (u, x->u->u)
list_cata :: List_alg x u -> [x] -> u list_cata (a,f) = cata where
  cata[] =a
  cata (x:l) = f x (cata l)

因此,如果我们想创建一个新函数prod,它将为我们提供列表中所有元素的乘积,我们可以通过以下方式创建:

prod = list_cata (1, (*))

这是我目前所拥有的:

type ('a, 'b) List_alg = 'b * ('a -> 'b -> 'b)

fun list_cata (a, f) List_alg: 'a list -> 'b = 
  let
  fun cata (xs: 'a list) : 'b  = 
      case xs of
      [] => a
    | x::xs => f x (cata xs)
  in
    cata
  end

val prod = list_cata (1, fn (x,y) => x*y)

当 list_cata 函数编译时,是 prod 给了我错误。到目前为止我得到的错误是:

Error: operator and operand do not agree [overload conflict]
  operator domain: [int ty] * ([* ty] * [* ty] -> [int ty] -> [int ty])
  operand:         [int ty] * ([* ty] * [* ty] -> [* ty])
  in expression:
    list_cata (1,(fn (<pat>,<pat>) => <exp> * <exp>))

我不太明白这里有什么问题。任何帮助将不胜感激!

【问题讨论】:

  • 你写的函数需要一个柯里化函数f,但你传递的是一个未柯里化的版本。

标签: haskell functional-programming sml fold smlnj


【解决方案1】:

您收到错误消息

Error: operator and operand do not agree [overload conflict]
  operator domain: [int ty] * ([* ty] * [* ty] -> [int ty] -> [int ty])
  operand:         [int ty] * ([* ty] * [* ty] -> [* ty])
  in expression:
    list_cata (1,(fn (<pat>,<pat>) => <exp> * <exp>))

因为线

val prod = list_cata (1, fn (x,y) => x*y)

具体来说,您传递的元组的第二个元素是类型[* ty] * [* ty] -&gt; [* ty]。相比之下,您期望的类型是 'a -&gt; 'b -&gt; 'b 的实例。因此,出现这种情况是因为您在想要一个咖喱函数的地方使用了一个非咖喱函数。

假设我们修改为

type ('a, 'b) List_alg = 'b * ('a -> 'b -> 'b)

fun list_cata (a, f) List_alg: 'a list -> 'b = 
  let
  fun cata (xs: 'a list) : 'b  = 
      case xs of
      [] => a
    | x::xs => f x (cata xs)
  in
    cata
  end

fun curry f a b = f (a, b)
val prod = list_cata (1, curry op*) (* like ( * ) in haskell *)

如果你这样做,你会得到一个相当奇怪的prod 类型,可能不是你想要的。我不太清楚这里的类型推断是如何工作的,尽管有人比我有更多的经验可以评论,但据我了解,你最终会遇到一个问题,你想要在非扩展表达式中成为多态函数(let 表达式)并因此调用 SML 的 value restriction

我认为您可以通过仅在列表中进行模式匹配来进一步简化代码,而不是像这样在 let 中使用 fun 绑定

fun ('a, 'b) list_cata (f : 'a -> 'b -> 'b) (z : 'b) ([ ] : 'a list) : 'b = z
           | list_cata f z (x::xs) = f x (list_cata f z xs)

fun curry f a b = f (a, b)
val prod = list_cata (curry op*) 1

【讨论】:

  • 你是对的,我们正在达到价值限制。问题只是list_cata 试图采用另一个名为List_alg 的参数,但没有在函数体的任何地方使用它。这可以完全删除,然后 prod 将具有正确的类型。
  • 在您第一次修订的list_cata 上,SML 分配类型'a * ('b -&gt; 'a -&gt; 'a) -&gt; 'c -&gt; 'b list -&gt; 'a。注意额外参数的错误'c 类型参数;)
  • 啊,我错过了一个事实,即它甚至没有被用作原始类型中的正确类型注释!这就解释了我找不到来源的额外参数。
猜你喜欢
  • 2020-08-15
  • 2020-08-23
  • 2013-12-23
  • 2012-05-26
  • 1970-01-01
  • 1970-01-01
  • 2021-09-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多