我很难理解Haskell中类型签名背后的推理。
1)当->
被说成是右结合的,这是否意味着它可以用类似的方式来理解,例如4^(2^(3^2))?
2)使用简单函数的类型签名来表达我的怀疑(为了解释我的理解方式,我将使用a
,b
,c
而不是Num a => a
或Int
):
myAdd :: a -> b -> c
myAdd x y = x+y
字符串
这意味着函数接受参数a
并返回接受b
并最终返回c
的函数
但它可以重写为:
myAdd :: (a->(b->c))
型
正如大多数学习材料所述,c
在我们的示例中是函数myAdd的结果,为什么根据括号的使用,它表明第一个“操作”是b->c
?我如何从类型签名推断出执行操作的顺序?
3)我接到一个任务
map f xs
型
使用foldr
、(.)
和(:)
,结果是:
map f xs = foldr ((:) . f) [] xs
型
我没有问题理解上述函数的工作原理,但在这里我们又来了-类型签名。如果我们假设,名称是统一的,所以类型a
在所有合同中表示相同的类型,似乎,c
和d
可以用a
和b
表示。在数学中,类似任务可能非常简单,但在Haskell中如何实现呢?
map :: (a -> b) -> [a] -> [b]
foldr :: (a -> c -> c) -> c -> [a] -> c
(:) :: b -> ([b] -> [b])
(.) :: (b -> d) -> (a -> b) -> a -> d
型
2条答案
按热度按时间y0u0uwnf1#
使用你的符号,在
字符串
你正确地将类型解释为
a -> (b->c)
,但你继续暗示b -> c
中的计算以某种方式首先完成。当计算
myAdd 2 10
这样的值时,函数的计算是从左到右的。1)首先对
myAdd 2
进行求值。此求值的结果是将给定数字y
发送到2 + y
的函数。实际上,myAdd
的定义与以下相同:型
2)然后将最后一个函数应用于参数
10
,得到2 + 10 = 12
因此,
->
在 * 类型表达式 * 中的右结合性并不对应于 * 函数求值 * 中从右到左的计算顺序。事实上,函数求值是左结合的:myAdd 2 10
与(myAdd 2) 10
相同。xoshrz7s2#
在类型签名中,用“右结合性”这个术语来表示默认情况下不可见的括号是非常容易误导的。
在数学中,相同的符号在不同的领域和研究中表示不同的含义和用法。
显式或不可见的括号并不像算术优先级那样指示结合性。
在算术中,最里面的圆括号的计算首先计算最外面的圆括号。
而在Haskell的类型系统中,圆括号只表示另一个函数返回的函数,该函数在“->”符号之前接受前一个类型的参数,这是一个函数,该函数接受“->”符号之后的类型的参数,然后返回另一个函数,依此类推,直到某个函数返回最终结果。
例如:假设我们定义了一个函数,该函数接受三个类型参数,这些参数在类型类“”中被约束,并对所有给定的数字进行求和。
字符串
当从ghci中的文件加载第二个带有显式括号的示例时,它被成功编译。
这里的类型推理“(a ->(a ->(a -> a))”表示函数“sumThreeNums”首先接受类型“a”的第一个参数并返回另一个函数,
它是“(a ->(a -> a))",它接受类型为“a”的第二个参数并返回另一个函数,
它是“(a -> a)",接受类型为“a”的第三个参数,并返回类型为“a”的最终结果。
在实践中,显式括号通常用于指示参数是一个函数,并且我上面展示的currying过程默认情况下省略了括号。
在这里,Happy Hacking:)