我正在努力学习和理解Haskell的设计。我目前正在使用Lambda / Anonymous函数,我很想知道。
为什么不是Eq类的函数类型实例?
Prelude> (\z -> z + 5) == (+5)
在这个问题上,我想知道是否因为z可以是任何东西,甚至可能是一个自由变量,在所有lambda函数中,所以设置类型为Eq的lambda函数是一个设计缺陷。
为什么不是类型类的函数类型实例Show?
Prelude> (\q -> q - 2)
我感谢任何澄清。
非常感谢提前!
答案 0 :(得分:9)
这些功能是相同还是不同:
dbl1 :: Int -> Int
dbl1 x = x + x
dbl2 :: Int -> Int
dlb2 x = 2 * x
对于一些函数,编译器看到它们包含相同的逻辑是“容易的”。但是大多数功能都很难比较。然后有一些逻辑上不同的函数,但行为相同 - 如上面的dbl1
和dbl2
。因此,您必须做出选择,以针对每个可能的值测试它们,或者确定它们不相等。在大多数情况下,前者完全不切实际。后者绝对不可取或不直观。现在,请考虑问题已经难以解决,然后投入IO
...
答案 1 :(得分:6)
我认为戴夫和彼得都没有强调过的一个重要概念是:当且仅当(a)它们具有相同的类型时,两个函数是相等的,并且(b)对于每个可能的参数,你可以给出他们,他们都产生相同的结果。
现在,有了这个清楚,Eq
的答案就是他们所说的。 Peter指出函数的Eq
实例需要能够分析两个任意函数并正确地确定它们是否为任何两个输入产生相同的结果。正如戴夫指出的那样,这实际上在数学上是不可能的;任何试图比较任意函数的检查器都会因某些函数而失败 - 这意味着它会挂起或在某些情况下产生错误答案。
你会看到Haskell程序员一直在讨论函数的相等性,但是大多数时候他们的意思是人已经证明了两个函数是相等的。例如,函数组合运算符的定义如下:
(.) :: (b -> c) -> (a -> b) -> (a -> c)
f . g = \x -> f (g x)
我们现在可以证明所有可能的h :: c -> d
,g :: b -> c
和h :: a -> b
,f . (g . h) == (f . g) . h
。在这种情况下,这很容易,我们只是根据(.)
的定义扩展表达式,我们对两者都有相同的结论:
f . (g . h) = f . (\y -> g (h y)) -- expand `g . h` by definition
= \x -> f ((\y -> g (h y)) x) -- expand `f . (\y -> g (h y))`
= \x -> f (g (h x)) -- apply the inner lambda
(f . g) . h = (\y -> f (g y)) . h
= \x -> (\y -> f (g y)) (h x)
= \x -> f (g (h x))
但这只能用于精心挑选的功能,而计算机通常不能很好地或可靠地完成。对于你编写的任何程序来尝试测试任意函数的相等性,会有一些函数会产生错误的答案或永远循环。
答案 2 :(得分:4)
Gödel's incompleteness theorems意味着函数的任何Eq
实例必须提供不准确的结果或有时返回⊥。这不是我们对Eq
实例的期望(至少对于有限数据而言)。
show
应该提供评估其输入的Haskell源代码。编译Haskell程序时这很尴尬,因为现在你必须保留每个函数的源代码副本,膨胀可执行文件,即使函数的Show
实例从未使用过。
可以为违反此规则的函数提供Show
实例,例如:通过始终返回"{-function-}"
或(对于某些类型)返回函数的类型。早期版本的Haskell做到了。但有人认为违反这条规则不是一个好主意。
答案 3 :(得分:1)
我喜欢每个人的答案......他们似乎有道理。在这个阶段,我不会想象为什么函数没有默认设置为Eq和Show的实例。这只是一些实验,可能会为您提供自己尝试的想法:
Prelude> :set -XFlexibleInstances
Prelude> instance Eq (Int -> Int) where x == y = map x [0..10] == map y [0..10]
Prelude> ((\z -> z+5) :: Int -> Int) == ((+5) :: Int -> Int)
True
Prelude> instance Show (Int -> Int) where show x = show (zip [0..10] (map x [0..10]))
Prelude> (\q -> q-2) :: (Int -> Int)
[(0,-2),(1,-1),(2,0),(3,1),(4,2),(5,3),(6,4),(7,5),(8,6),(9,7),(10,8)]