如果函数的返回是class ClassA
,是否可以在此函数中返回ClassA
的任何实例?例如:someFunction :: (ClassA a) => String -> a
那么,为什么下面的这个功能不起作用?请注意,String
是Eq
getAnyEq :: (Eq a) => String -> a
getAnyEq input |input == "1" = "something"
|otherwise = "other"
发生的错误是:
Could not deduce (a ~ [Char])
from the context (Eq a)
bound by the type signature for getAnyEq :: Eq a => String -> a
at src/InterceptorRegistry.hs:11:13-33
`a' is a rigid type variable bound by
the type signature for getAnyEq :: Eq a => String -> a
at src/InterceptorRegistry.hs:11:13
我试图在互联网资源上找到这个确切的解释,但我没有找到......你能告诉我一些吗?
答案 0 :(得分:11)
类型Eq a => a
并不意味着“实现Eq
的类型”,而是“实现Eq
的任何类型。”例如,如果使用undefined实现函数:< / p>
getAnyEq :: (Eq a) => String -> a
getAnyEq str = undefined
以下函数正确编译(虽然在运行时会因未定义的错误而崩溃):
x,y,z :: Bool
x = getAnyEq "test" == "hello"
y = getAnyEq "test" == [Just (Right True)]
z = getAnyEq "test" == ("this", "sss")
无法为函数提供合适的实现,因为无法生成结果的值。
只有当类型变量具有包含返回值的函数的类的实例时,才返回类型变量的函数才有意义。例如,考虑Num类:
class (Eq a, Show a) => Num a where
(+) :: a -> a -> a
(*) :: a -> a -> a
(-) :: a -> a -> a
negate :: a -> a
abs :: a -> a
signum :: a -> a
fromInteger :: Integer -> a
(注意我在ghc的旧版本上测试了这个,你的Num可能没有Eq或Show约束)。
函数fromInteger
返回a(不需要a
作为输入),因此我们可以从该类型类中获得a
。有值后,可以使用其他功能。所以以下功能有效:
getANum:: (Num a) => String -> a
getANum "zero" = fromInteger 0
getANum "asdf" = fromInteger 46
getANum _ = fromInteger 1
> getANum "asdf"
46
请注意,由于文字整数被有效地解析为fromInteger <num>
,因此上述函数中的fromInteger
函数调用实际上并不是必需的。我只是将它们包括在内以显示它是如何工作的。
可用于检索值的其他常见类型类是:
Monad
(使用return
)Applicative
(使用pure
)Monoid
(使用mempty
)Read
(使用read
或其他任何其他功能)答案 1 :(得分:3)
除了@David Miani的精彩答案之外,我可以说标准Haskell类型系统中的每个函数类型声明都意味着forall
(或∀)量子:
getAnyEq :: (Eq a) => String -> a
在语义上等同于
getAnyEq :: forall a . (Eq a) => String -> a
您可以尝试使用{-# LANGUAGE ExplicitForall #-}
扩展程序。这意味着,对于每个类型a
,使用类型类Eq
进行约束,都会有一个具有给定类型的函数getAnyEq
。但是,您建议仅针对单个类型(String
)定义,而不是forall
。
我建议你的定义对另一个量子有效,∃:
getAnyEq :: exists a . (Eq a) => String -> a
它没有由GHC实现,但是例如UHC(Utrecht Haskell编译器)支持它。不幸的是,我目前无法尝试。
答案 2 :(得分:1)
在阅读了上面的答案以及本页顶部链接的相关主题后,我得出结论,解决方案是使用存在量化类型。
因此,getAnyEq
函数的解决方案是:
{-# LANGUAGE ExistentialQuantification #-}
data ShowEq = forall s. Eq s => SE s
getAnyEq :: String -> ShowEq
getAnyEq input |input == "1" = SE "ds"
|otherwise = SE "ss"
解释这些类型的一个非常有用的链接是:http://en.wikibooks.org/wiki/Haskell/Existentially_quantified_types