在Haskell中,我只知道
:type ((+)(1))
((+)(1)) :: Num a => a -> a
((+)(1) 2
3
但是怎么样
:type abs(sqrt)
abs(sqrt) :: (Floating a, Num (a -> a)) => a -> a
实际上,我尝试了很多次但是没有使用'abs(sqrt)'这个功能。然后我有几个问题。什么是类型(类?)'(浮动a,Num(a - > a))'?是否可以使用'abs(sqrt)'函数?怎么样?
答案 0 :(得分:1)
当你看到Num (a -> a)
时,通常意味着你在某个地方犯了错误。
也许你真的想要abs . sqrt
,其类型为Floating c => c -> c
- 即它是浮动类型(例如Float,Double)的函数,属于同一个浮动类型。
答案 1 :(得分:0)
可能无法使用此功能。
此处可能发生的是,该类型表明abs(sqrt)
具有a
必须属于类Floating
且(a -> a)
必须属于类{的约束{1}}。换句话说,Num
函数需要能够被视为数字。
不幸的是,sqrt
不属于类sqrt
,因此不会有任何输入在这里工作(不管它是否有意义)。但是,某些版本的GHCi允许您获得可能的类型。
请查看Haskell type length + 1类似问题。
正如ErikR所说,或许你打算写Num
。
答案 2 :(得分:0)
类型类是一种泛化函数的方法,这样它们可以是多态的,而其他类可以为它们自己的类型实现这些函数。以类型类Show
为例,其简化形式为
class Show a where
show :: a -> String
这表示实现Show
类型类的任何类型都可以转换为String
(对于更现实的约束,还有一些更复杂的问题,但是Show
的要点是能够将值转换为String
s)。
在这种情况下,函数show
具有完整类型Show a => a -> String
。
如果我们检查函数sqrt
,它的类型是
> :type sqrt
sqrt :: Floating a => a -> a
对于abs
:
> :type abs
abs :: Num b => b -> b
如果您询问GHCi的类型是什么,它会在两种情况下使用类型变量a
,但我在b
的类型签名中使用了abs
来明确这些是同名的不同类型变量,它有助于避免下一步的混淆。
这些类型签名意味着sqrt
获取其类型实现Floating
类型类的值(使用:info Floating
查看所有成员)并返回相同类型的值,并且abs
函数接受一个类型实现Num
类型类的值,并返回相同类型的值。
表达式abs(show)
被等效地解析为abs sqrt
,这意味着sqrt
是传递给abs
的第一个且唯一的参数。但是,我们只是说abs
的值为Num
类型,但sqrt
是函数,而不是数字。为什么Haskell接受这个而不是抱怨?当我们使用类型签名执行替换时,可以更清楚地看到原因。由于sqrt
的类型为Floating a => a -> a
,因此必须与b
的类型签名中的参数abs
匹配,因此将b
替换为Floating a => a -> a
我们得到abs sqrt :: (Floating a, Num (a -> a)) => a -> a
。
Haskell实际上允许函数类型实现Num
类型类,你可以自己做,尽管它可能是荒谬的。然而,仅仅因为某些东西对GHC来说似乎没有意义,只要这些类型可以干净利落地解决它就会允许它。
你无法真正使用这个功能,它只是没有意义。任何Num (a -> a)
都没有a
的内置实例,因此您必须定义自己的abs
。但是,您可以使用合成运算符sqrt
撰写函数.
和> :type abs . sqrt
abs . sqrt :: Floating c => c -> c
:
myfunc x = abs (sqrt x)
这确实有意义。此功能相当于
x
请注意,sqrt
首先应用于abs
,然后将该计算的结果传递给sqrt
,而不是将函数abs
传递给{{} 1}}。