我今天玩弄拥抱和被困在一个非常简单的问题:Haskell中的(1 2)类型是什么?
λ 1 1
:: (Num a, Num (a -> t)) => t
什么将这种类型的呢?我无法阅读此内容。
如果它有一个类型,为什么?我猜想表达式1 1
是格式不正确的,因此类型检查失败,这由Haskell编译器支持。
我今天玩弄拥抱和被困在一个非常简单的问题:Haskell中的(1 2)类型是什么?
λ 1 1
:: (Num a, Num (a -> t)) => t
什么将这种类型的呢?我无法阅读此内容。
如果它有一个类型,为什么?我猜想表达式1 1
是格式不正确的,因此类型检查失败,这由Haskell编译器支持。
不,没有形成不良。这种类型很奇怪,可能没有任何有意义的值,但它仍然是允许的。
请记住,文字被重载。 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
其中f
和g
在返回的数字功能。
使用上述实例声明1 2
将等于1
。 基本上用作上述实例的函数的字面量等于const <that-literal>
。
在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
当你将函数变成'Num'的实例时,它会引起一些混乱,但我不会说没有人会这么做。它同样适用于函数的'Monoid'实例:例如你可以写一些类似'(+5)*(+3)'的函数,并得到一个新的函数,该函数执行'\ x - >(x + 5)*(x + 3)',我觉得这很酷。另请参阅[这里](https://wiki.haskell.org/Num_instance_for_functions)。 –
顺便问一下,有没有例如'1 2'或'True“hello”'或''hello“[1,2,3]''等有用的表达式的实际例子? DSL我猜? –
'True'不会被重载 - 它是'data Bool = False |的实际构造函数。 True'数据类型 – Fraser
@ErikAllik我从来没有见过这种方式。这可能是可能的,但AFAIK不被使用。 – Bakuriu