在Haskell中,为什么编译:
splice :: String -> String -> String
splice a b = a ++ b
main = print (splice "hi" "ya")
但这不是:
splice :: (String a) => a -> a -> a
splice a b = a ++ b
main = print (splice "hi" "ya")
>> Type constructor `String' used as a class
我原以为这些都是一样的。有没有办法使用第二种样式,避免重复类型名称3次?
答案 0 :(得分:13)
类型中的=>
语法适用于typeclasses。
当您说f :: (Something a) => a
时,您并不是说a
是Something
,而是说它是“一组“Something
类型。
例如,Num
是一个类型类,包括Int
和Float
等类型。
但是,没有类型Num
,所以我不能说
f :: Num -> Num
f x = x + 5
但是,我可以说
f :: Int -> Int
f x = x + 5
或
f :: (Num a) => a -> a
f x = x + 5
答案 1 :(得分:3)
实际上,有可能:
Prelude> :set -XTypeFamilies
Prelude> let splice :: (a~String) => a->a->a; splice a b = a++b
Prelude> :t splice
splice :: String -> String -> String
这使用等式约束~
。但是我会避免这种情况,它不仅仅是简单地编写String -> String -> String
,而是更难以理解,并且编译器难以解决。
答案 2 :(得分:3)
有没有办法使用第二种样式,避免重复类型名称3次?
为简化类型签名,您可以使用类型同义词。例如,你可以写
type S = String
splice :: S -> S -> S
或类似
type BinOp a = a -> a -> a
splice :: BinOp String
然而,对于像String -> String -> String
这样简单的事情,我建议只输入它。类型同义词应该用于使类型签名更具可读性,而不是更少。
在这种特殊情况下,您还可以将类型签名概括为
splice :: [a] -> [a] -> [a]
因为它根本不依赖于元素。
答案 3 :(得分:1)
嗯...... String
是一种类型,你试图将它用作一个类。
如果您想要splice
函数的多态版本示例,请尝试:
import Data.Monoid
splice :: Monoid a=> a -> a -> a
splice = mappend
编辑:所以这里的语法是=>
左边出现的大写字是类型类约束变量显示在{{1}的右侧}。右边的所有大写单词都是 types
答案 4 :(得分:1)
您可以在this Learn You a Haskell章节中找到解释。