我不明白为什么Haskell无法在下面的代码中找出第8行的类型。 expressMaybe函数的类型签名是否确定结果类型与两个输入参数的类型相同?
{-# LANGUAGE MultiParamTypeClasses #-}
class Gene g n where
express :: g -> g -> g
-- there will be other functions that use the "n" type parameter
expressMaybe :: Gene g n => Maybe g -> Maybe g -> Maybe g
expressMaybe (Just a) (Just b) = Just (express a b) -- line 8
expressMaybe (Just a) Nothing = Just a
expressMaybe Nothing (Just b) = Just b
expressMaybe Nothing Nothing = Nothing
我得到的错误是:
Amy20.hs:8:40:
Ambiguous type variable `n0' in the constraint:
(Gene g n0) arising from a use of `express'
Probable fix: add a type signature that fixes these type variable(s)
In the first argument of `Just', namely `(express a b)'
In the expression: Just (express a b)
In an equation for `expressMaybe':
expressMaybe (Just a) (Just b) = Just (express a b)
Failed, modules loaded: none.
我尝试使用RankNTypes和ScopedTypeVariables,但我无法弄清楚如何使错误消失。
提前感谢您的帮助!
编辑:现在我理解了这个问题,我使用了fundeps,因为我对它们很熟悉,对于我的应用程序来说,对于编码基因有一个以上的“字母表”没有多大意义。我以前从未使用过类型系列,所以我也会研究它。
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}
class Gene g n | g -> n where
express :: g -> g -> g
-- there will be other functions that use the "n" type parameter
expressMaybe :: Gene g n => Maybe g -> Maybe g -> Maybe g
expressMaybe (Just a) (Just b) = Just (express a b) -- line 8
expressMaybe (Just a) Nothing = Just a
expressMaybe Nothing (Just b) = Just b
expressMaybe Nothing Nothing = Nothing
答案 0 :(得分:12)
考虑一下:
instance Gene String Int where
express _ _ = "INT"
instance Gene String Double where
express _ _ = "DOUBLE"
expressMaybe (Just "") (Just "")
该代码应该生成(Just "INT")
还是(Just "DOUBLE")
?是的,Haskell知道expressMaybe
的结果与参数的类型相同。但这并不意味着它知道在这里使用哪个实例,因为对于具有不同g
的相同类型n
,可能存在多个实例。
如果在您的情况下,每种类型n
只会有一种类型g
,您可以考虑使用类型系列或函数依赖项等扩展,您可以使用这些类型向类型系统表达该事实
答案 1 :(得分:1)
我建议你避免功能依赖,并选择类型系列。它们更有趣,更直观:
{-# LANGUAGE TypeFamilies, KindSignatures #-}
class Gene g where
type Nucleotide g :: * -- each instance has an associated type
express :: g -> g -> g
encode :: [Nucleotide g] -> g -- probably doesn't make sense, but need an example
-- there will be other functions that use the "Nucleotide g" type parameter
假设我们有
data ACTG = A | C | T | G
data ACTGgene = ACTGgene [ACTG]
基本上,您可以通过类型级别的简单模式匹配来定义类型函数:
instance Gene ACTGgene where
type Nucleotide ACTGgene = ACTG
encode ns = ACTGgene ns
express = error "I'm out of my depth here because I gave up Biology when I hit 14."
现在我们的代码编译:
expressMaybe :: Gene g => Maybe g -> Maybe g -> Maybe g
expressMaybe (Just a) (Just b) = Just (express a b) -- compiles fine
expressMaybe (Just a) Nothing = Just a
expressMaybe Nothing (Just b) = Just b
expressMaybe Nothing Nothing = Nothing
现在可能是你的基因类型基本上取决于你正在使用的核苷酸,或者 也许你可以互换使用不同的核苷酸,我不知道,但一个可能的解决方案 你的问题是改为使用构造函数类:
class Gene g where
express :: g n -> g n -> g n
encode :: n -> g n
-- more stuff
这适用于像
这样的数据声明data ACTG = A | C | T | G
data ListGene n = ListGene [n]
instance Gene ListGene where
...
但也许这对你的问题领域来说过于参与,我不知道。
当然你应该尝试打字。我做到了。 Now I love them. - 链接的答案包括最后的链接以供进一步阅读。