2015-10-13 75 views
6

我今天玩弄拥抱和被困在一个非常简单的问题:Haskell中的(1 2)类型是什么?

λ 1 1 
:: (Num a, Num (a -> t)) => t 

什么将这种类型的呢?我无法阅读此内容。

如果它有一个类型,为什么?我猜想表达式1 1是格式不正确的,因此类型检查失败,这由Haskell编译器支持。

回答

12

不,没有形成不良。这种类型很奇怪,可能没有任何有意义的值,但它仍然是允许的。

请记住,文字被重载。 1不是整数。这是任何类型的东西Num。功能是而不是排除在外。没有规则说a -> t不能是“一个数字”(即Num的一个实例)。

例如,你可以有一个instance声明,如:

instance Num a => Num (a -> b) where 
    fromInteger x = undefined 
    [...] 

现在1 1,简直是等于undefined。不是很有用,但仍然有效。

可以具有Num功能的有用定义。例如,从wiki

instance Num b => Num (a -> b) where 
    negate  = fmap negate 
     (+)   = liftA2 (+) 
     (*)   = liftA2 (*) 
     fromInteger = pure . fromInteger 
     abs   = fmap abs 
     signum  = fmap signum 

有了这个,你可以写的东西,如:

f + g 

其中fg在返回的数字功能。

使用上述实例声明1 2将等于1。 基本上用作上述实例的函数的字面量等于const <that-literal>

+0

顺便问一下,有没有例如'1 2'或'True“hello”'或''hello“[1,2,3]''等有用的表达式的实际例子? DSL我猜? –

+1

'True'不会被重载 - 它是'data Bool = False |的实际构造函数。 True'数据类型 – Fraser

+0

@ErikAllik我从来没有见过这种方式。这可能是可能的,但AFAIK不被使用。 – Bakuriu

5

在Haskell中,1没有固定类型。它是“任何数字类型”。更确切地说,任何实现类Num的类型。

具体而言,功能类型Num的实例在技术上是有效的。没有人会这样做,但从技术上讲这是可能的。

因此,编译器被假定第一1是某种数字功能的类型,然后将1是任何其他类型的数(可以是相同的类型,可能的不同的一个)。如果我们改变了表达,比方说,3 6,那么编译器是假设

3 :: Num (x -> y) => x -> y 
6 :: Num x => x 
3 6 :: (Num (x -> y), Num x) => y 
+1

当你将函数变成'Num'的实例时,它会引起一些混乱,但我不会说没有人会这么做。它同样适用于函数的'Monoid'实例:例如你可以写一些类似'(+5)*(+3)'的函数,并得到一个新的函数,该函数执行'\ x - >(x + 5)*(x + 3)',我觉得这很酷。另请参阅[这里](https://wiki.haskell.org/Num_instance_for_functions)。 –

相关问题