我一直在玩Haskell类型类,我面临一个问题,我希望有人能帮我解决。考虑到我来自Swift背景并试图将一些面向协议的知识移植到Haskell代码中。Type Classe实例列表
起初我宣布了一堆JSON解析器其中有相同的结构,只是不同的实现:
data Candle = Candle {
mts :: Integer,
open :: Double,
close :: Double
}
data Bar = Bar {
mts :: Integer,
min :: Double,
max :: Double
}
然后,我决定创建一个“类”,将定义其基本操作:
class GenericData a where
dataName :: a -> String
dataIdentifier :: a -> Double
dataParsing :: a -> String -> Maybe a
dataEmptyInstance :: a
instance GenericData Candle where
dataName _ = "Candle"
dataIdentifier = fromInteger . mts
dataParsing _ = candleParsing
dataEmptyInstance = emptyCandle
instance GenericData Bar where
dataName _ = "Bar"
dataIdentifier = fromInteger . mts
dataParsing _ = barParsing
dataEmptyInstance = emptyBar
我的第一个代码的气味是需要包括“一”,当它不需要(dataName
或dataParsing
),但随后我继续。
analyzeArguments :: GenericData a => [] -> [String] -> Maybe (a, [String])
analyzeArguments [] _ = Nothing
analyzeArguments _ [] = Nothing
analyzeArguments name data
| name == "Candles" = Just (head possibleCandidates, data)
| name == "Bar" = Just (last possibleRecordCandidates, data)
| otherwise = Nothing
possibleCandidates :: GenericData a => [a]
possibleCandidates = [emptyCandle, emptyBar]
现在,当我要选择,如果这两种情况下,应选择进行解析,我总是得到以下错误
• Couldn't match expected type ‘a’ with actual type ‘Candle’
‘a’ is a rigid type variable bound by
the type signature for:
possibleCandidates :: forall a. GenericData a => [a]
at src/GenericRecords.hs:42:29
我的目标是创建的GenericData
因为其他实例的列表功能取决于被选择执行正确的dataParser
。我知道这与类型检查程序* -> Constraint
有关,但仍未找到解决此冲突的方法。我已经使用了几个GHC语言扩展,但没有一个解决了这个问题。
我认为这里的代码味道可能是你的类型类。每当我看到类型类的方法都以'a'作为第一个参数时,我就会怀疑有人试图将面向对象类放在Haskell类型类中。这可能听起来像你想把'Bar'和'Candle'构造函数放在同一个ADT下。 – Alec
我认为这会很快下降到一个已知的[反模式](https://lukepalmer.wordpress.com/2010/01/24/haskell-antipattern-existential-typeclass/)。 – chi
两个评论什么是错误的(没有提出解决方案)。 1.列表是同类的(所有元素都具有相同的类型),因此'[emptyCandle,emptyBar]'是正确的。 2.'Foo a => [a]'类型给用户这个值控制选择'Foo'的哪个实例;实现者必须准备产生一个* any类型的值的列表,这是'Foo'的一个实例,而你似乎认为这种类型的实现者可以选择*他们最喜欢的*类型,这是一个实例'Foo'。 –