我在这里使用了这个Haskell解释器:https://tryhaskell.org/
当我提供输入5 1
时,它告诉我 - 我认为它是类型 - 表达式是(Num a, Num (a -> t)) => t
类型:
λ 5 1
:: (Num a, Num (a -> t)) => t
现在我试图理解如何解释这一点,这就是我想出来的。
a
是Num
类型,a -> t
也是t
类型。表达式导致某些类型1
通过理论上将a
(类型5
)应用于a -> t
(类型Num (a -> t)
)而生成。
这真让我感到不安,因为我看不出约束Num
是如何有意义的。从理论上讲,它看起来是正确的解释,但我无法找到证据。
这是有道理的,因为{{1}}是一个多态类型 - 它可以是一个函数。
答案 0 :(得分:9)
数字在Haskell中是多态的。当你写像
这样的东西5
编译器将其转换为fromInteger (5 :: Integer) :: Num a => a
。编译器事先并不知道要使用哪个实例,因此它最好从上下文中猜测。如果你有5 1
,那么第一个数字是多态Num
类型,它也必须是一个函数。第二个数字只是Num
,所以这很正常。
但你可能会问"一个数字怎么能成为一个函数?"如果世界上的一切都有意义,那么数字就不是函数,但你实际上可以为它们编写一个或多或少的实例:
{-# LANGUAGE FlexibleInstances #-}
instance Num a => Num (a -> a) where
fromInteger a = const (fromInteger a)
a + b = \c -> a c + b c
a * b = \c -> a c * b c
abs a = \c -> abs (a c)
signum a = \c -> signum (a c)
negate a = \c -> negate (a c)
这满足了定义,但它可能不是非常有用。例如:
> let x = 1 :: Int -> Int; y = 2 :: Int -> Int
> x + y $ 0
3
> x + y $ 102089
3
> x + y $ undefined
3
所以在这里,论证与表达无关,它甚至没有被评估。如何更有趣的一个:
> let x = (+10); y = (*10)
> x + y $ 0 -- x 0 + y 0 = 0 + 10 + 0 * 10
10
> x + y $ 1 -- x 1 + y 1 = 1 + 10 + 1 * 10
21
> x + y $ 2
32
等等。我确定有人可以找到一个有趣的用例,但我不推荐它,它显然不是很直观。
答案 1 :(得分:2)
在Haskell中,数字是多态的:
λ> :t 5
5 :: Num a => a
重要这里需要注意的是Haskell中的函数应用程序是空白。因此,要制作类似5 2
类型检查的内容,您只需为(a -> a)
类型创建一个实例。
答案 2 :(得分:1)
您的解释是正确的。
我没有看到约束Num(a - > t)是否有意义。
这里的关键是任何事物都可以是Num
类型,只要代码中的某个地方有一个实例声明即可。因此,对于某些a
和t
(a
为Num
类型),您编写了instance Num (a -> t) where ...
,那么a -> t
将是{ {1}}类型和Num
实际上可以评估为值。