【问题标题】:Determining the type of a function in Functional Programming在函数式编程中确定函数的类型
【发布时间】:2012-04-14 04:10:35
【问题描述】:

以下等式是用 Miranda 语法编写的,但由于 Miranda 和 Haskell 之间的相似之处,我希望 Haskell 程序员应该理解它!

如果你定义了以下函数:

rc v g i = g (v:i)
rn x = x
rh g = hd (g [])


f [] y = y 
f (x:xs) y = f xs (rc x y)

g [] y = y
g (x:xs) y = g xs (x:y)

你如何计算出函数的类型?我想我知道如何为 f、g 和 rn 解决这个问题,但我对部分应用程序部分感到困惑。

rn 将是 * -> *或任何东西 -> 任何东西,我认为它是 Haskell 中的 a -> a?

对于 f 和 g,函数类型是否都是 [*] -> * -> *

我不确定如何找到 rc 和 rh 的类型。在 rc 中,g 被部分应用于变量 i - 所以我猜测这将 i 的类型限制为 [*]。 rc 的定义中 rc 和 g 的顺序是什么? g 是否应用于 i,然后将生成的函数用作 rc 的参数?或者 rc 是否采用 v、g 和 i 的 3 个单独参数?我真的很困惑..任何帮助将不胜感激!谢谢大家。

抱歉忘了加上 hd 是列表的标准头函数,定义为:

hd :: [*] -> *
hd (a:x) = a
hd [] = error "hd []"

【问题讨论】:

  • 不,我现在正在准备考试,这是米兰达考试的老问题。
  • hd函数的类型是什么?
  • 抱歉忘记添加该定义 - 我现在已将其添加到问题中!

标签: types definition


【解决方案1】:

类型是从已知的类型和定义中如何使用表达式推断出来的。

让我们从顶部开始,

rc v g i = g (v : i)

所以rc :: a -> b -> c -> d 我们必须看看可以找到关于a, b, cd 的信息。在右边,出现(v : i),所以v :: a,我们看到i :: [a]c = [a]。然后g被应用到v : i,所以g :: [a] -> d,一共,

rc :: a -> ([a] -> d) -> [a] -> d

rn x = x表示rn的参数类型没有限制,返回类型相同,rn :: a -> a

rh g = hd (g [])

由于rh 的参数g 应用于RHS 上的一个空列表,它必须具有[a] -> b 类型,可能还有关于ab 的更多信息。确实,g [] 是 RHS 上hd 的参数,所以g [] :: [c]g :: [a] -> [c],因此

rh :: ([a] -> [c]) -> c

下一个

f [] y = y 
f (x:xs) y = f xs (rc x y)

第一个参数是一个列表,如果它为空,则结果是第二个参数,所以f :: [a] -> b -> b 来自第一个等式。现在,在第二个等式中,在 RHS 上,f 的第二个参数是rc x y,因此rc x y 必须与y 具有相同的类型,我们称之为b。但是

rc :: a -> ([a] -> d) -> [a] -> d

,所以b = [a] -> d。因此

f :: [a] -> ([a] -> d) -> [a] -> d

终于

g [] y = y
g (x:xs) y = g xs (x:y)

我们从第一个等式推导出g :: [a] -> b -> b。从第二个,我们推导出b = [a],因为我们取g的第一个参数的头部并将它的cons到第二个,因此

g :: [a] -> [a] -> [a]

【讨论】:

  • 谢谢丹尼尔!对于第一个方程 rc,我们将 g 应用于我们已确定为类型 [a] 的 i - 但是我们如何知道函数的输出是类型 d?这不就是rc的唯一输出,g的输出也不一定是这样吗?
  • rc的定义中我们对g的结果类型一无所知,所以无论传递的参数g的结果类型是什么rc 在那次通话中。对于可以是任何类型的类型,我们使用类型变量,无论我们称之为d 还是simon 都无关紧要。这里我们不能称它为a,因为它已经用于另一种类型(但是传递g1 :: [b] -> b是合法的,类型d可能等于a,但它不需要,因此它得到不同的表示)。我把它留给了d,因为这是rc 类型的第一个近似结果类型。
  • 如果rc的结果只是另一个g函数,为什么rc的输出不是[a] -> d?制作整个事情:rc :: a -> ([a] -> d) -> [a] -> ([a] -> d)
  • rc 的结果不是另一个g 函数,它是应用的结果 g to (v:i),所以rc 的结果类型是 g 的结果类型。
  • 啊!知道了!谢谢你这么耐心!
【解决方案2】:

我将使用haskell语法来编写类型。

rc v g i = g (v:i)

这里rc 接受三个参数,所以它的类型类似于a -> b -> c -> dv:i 必须是与vi 相同类型的元素的列表,所以v :: ai :: [a]g 应用于该列表,因此 g :: [a] -> d。 如果你把所有东西放在一起,你会得到rc :: a -> ([a] -> d) -> [a] -> d

正如你已经知道rn :: a -> a,因为它只是身份。

我不知道你在rh 中使用的hd 函数的类型,所以我会跳过。

f [] y = y 
f (x:xs) y = f xs (rc x y)

这里f 有两个参数,所以它的类型类似于a -> b -> c。 从第一种情况我们可以推断出b == c,因为我们返回y,并且第一个参数是一个列表。 现在我们知道f :: [a'] -> b -> b。 在第二种情况下,注意xy 是如何在rc 的输入中给出的:y 必须是函数[a'] -> drc x y :: a' -> d(这也必须是y 的类型,因为它作为f 的第二个参数传递)。 最后,我们可以说f :: [a'] -> ([a'] -> d) -> ([a'] -> d)。由于-> 是右关联的,这相当于[a'] -> ([a'] -> d) -> [a'] -> d

你可以用同样的方式推理其余的。

【讨论】:

  • hd 来自 Miranda 标准库。相当于Haskell中的head,所以它的类型是[a] -> a
  • 谢谢里卡多!您能否看看我问丹尼尔的问题,因为它也适用于您的回答 - 谢谢!
  • 很高兴。对不起,我来晚了。他已经向你解释过:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-04
  • 2010-09-06
相关资源
最近更新 更多