Functional programming 函数的ML类型,一个小提示?

Functional programming 函数的ML类型,一个小提示?,functional-programming,ml,Functional Programming,Ml,我准备考试。最古老的问题之一是我们不熟悉的。请一些专家为我们澄清这一点 以下哪一项可以是后续ML函数的类型 答题纸上说(1)是正确的。注释或简短描述,以便更好地理解?您应该做的第一件事是自己重写函数定义。这将迫使您实际解析和理解它 fun f (g, nil) = nil | f (g, x :: xs) = (fn a => g (a, x)) :: f (g, xs); 所以,f是一个函数,甚至问题是,它必须有类型…->: val f : ... -> ... 它

我准备考试。最古老的问题之一是我们不熟悉的。请一些专家为我们澄清这一点

以下哪一项可以是后续ML函数的类型


答题纸上说(1)是正确的。注释或简短描述,以便更好地理解?

您应该做的第一件事是自己重写函数定义。这将迫使您实际解析和理解它

fun f (g, nil)     = nil
  | f (g, x :: xs) = (fn a => g (a, x)) :: f (g, xs);
所以,
f
是一个函数,甚至问题是,它必须有类型
…->

val f : ... -> ...
它收到了什么?让我们来看一下函数的第一种模式:

fun f (g, nil)     = nil
val f : ((('a * 'b) -> 'c) * ... list) -> (... -> ...) list
它的形式是
(a,b)
,它是一个2元组。函数的参数必须是元组,然后:

val f : (... * ...) -> ...
仅通过查看定义,我们无法确定
g
必须具有什么类型,但它使用
nil
作为元组的第二个元素,而
nil
是空列表。这意味着元组的第二个组件必须是以下内容的列表:

val f : (... * ... list) -> ...
我们还能推断出什么?返回值也是
nil
,这意味着函数返回一个某物列表,不清楚该某物是什么

好,现在让我们跳到函数定义的第二种模式:

| f (g, x :: xs) = (fn a => g (a, x)) :: f (g, xs);
我们没有找到关于参数类型的更多信息,只是确认了元组的第二个元素确实必须是列表,因为它使用了
构造函数

让我们来看看尸体:

(fn a => g (a, x)) :: f (g, xs)
看起来它正在构建一个列表,所以它必须返回一个列表,这与我们到目前为止绘制的返回类型一致,即,
。。。列表
。让我们 试着找出元素的类型

它似乎添加了一个函数对象作为通过递归调用函数
f
构建的列表的开头,我们目前正在研究这个函数。所以我们返回的列表元素必须是函数:

val f : (... * ... list) -> (... -> ...) list
但是这个函数做什么呢?它使用2元组参数调用
g
。现在我们可以填写一些关于2元组
f
receives的第一个元素的信息。它必须是一个同时接收2元组的函数:

val f : (((... * ...) -> ...) * ... list) -> (... -> ...) list
对于添加到返回列表中的函数literal接收到的
参数,我们可以说些什么吗?不是真的,只是它被传递给了
g
。我们能告诉你关于
x
的类型吗?不是真的,只是它被传递给了
g
。此外,
a
x
之间是否存在任何约束?看起来不像。到目前为止,我们只能判断
g
的类型必须如下所示:

('a * 'b) -> 'c'
其中
'a
'b
'c
是多态类型,即任何具体类型都可以满足它们。你可以将它们视为整体。现在,我们可以为
f
函数填写更多类型:

fun f (g, nil)     = nil
val f : ((('a * 'b) -> 'c) * ... list) -> (... -> ...) list
实际上,我们可以做更多的事情,我们已经为
x
变量指定了一个类型,但是这来自
f
接收的2元组的第二个参数,所以我们也来填写这个参数:

val f : ((('a * 'b) -> 'c) * 'b list) -> (... -> ...) list
我们甚至可以填写返回列表的元素类型,因为我们已经为它分配了类型

val f : ((('a * 'b) -> 'c) * 'b list) -> ('a -> 'c) list
由于类型运算符的优先规则,我们可以在不改变含义的情况下从我们提出的类型中删除一些额外的括号:

val f : ('a * 'b -> 'c) * 'b list -> ('a -> 'c) list
现在,我们的函数类型已完成。但是,在可能的答案列表中找不到这种类型的答案,因此我们必须看看是否可以使用其中的任何一种来代替我们已经确定的答案。为什么?因为我们的函数类型使用类型变量,可以用具体类型填充。让我们一个接一个地看:

选择1 它看起来像
'a
可能是
int
'b
可能是
bool
(这是你粘贴的
书,但我假设它是打字错误,
'c
可能是真的。所有替换都匹配这些对应,因此我们声明,是的,第一个选项可以是给定函数的可能类型,即使不是最通用的类型。让我们做第二个选择:

选择2 混凝土类型对应表的类型变量可以是:

  • 'a
    ->
    bool
  • 'b
    ->
    int
  • 'c
    ->
    int
  • 'b
    ->
    real
我们可以停在这里,因为我们可以看到
'b
被分配给了不同的类型,所以这个函数签名不能分配给我们已经给出的实现

选择3和4
它们与选项2相似,但我将让它们作为读者的练习:)

非常好!真让我吃惊!所以你同意选择(1)是正确的。有没有选择(1)的快速方法?@user3661613考虑到当前的练习和可能的选择,我看不到任何快速方法。请你说简单一点,你的句子“它似乎添加了一个函数对象作为递归调用函数f构建的列表的开头,我们目前正在研究这个函数。”
val f : ('a  * 'b   -> 'c)   * 'b list   -> ('a  -> 'c) list
val f : (int * bool -> real) * bool list -> (int -> real) list
val f : ('a   * 'b  -> 'c)  * 'b list   -> ('a   -> 'c) list
val f : (bool * int -> int) * real list -> (bool -> int) list