我有一些类型实例。我们将它们称为A,B和C。它们都是类型类X的实例。现在,我想创建一个单独的函数create
,该函数在给定某些输入的情况下创建A,B或C的实例(比如说一个字符串)。类型系统无法知道什么输入将提供什么类型。那是Haskell不喜欢的东西,我想我知道答案,但我想确定。我得到的当前错误是:
• Couldn't match expected type ‘c’ with actual type ‘GCCCommand’
‘c’ is a rigid type variable bound by
the type signature for:
compiler :: forall c. CompilerCommand c => String -> c
at src/System/Command/Typed/CC.hs:29:1-44
• In the expression: gcc path
In an equation for ‘compiler’:
compiler path
| exe == "g++" || exe == "gcc" || exe == "cc" || exe == "cpp"
= gcc path
where
exe = takeFileName path
• Relevant bindings include
compiler :: String -> c
(bound at src/System/Command/Typed/CC.hs:31:1)
我怀疑这是否意味着在这种特殊情况下不可能在返回类型上重载,因为编译器无法预先知道数据在内存中的外观?您将如何实现此功能?我正在考虑创建类似以下的内容:
data SuperX = SuperA A | SuperB B | SuperC C
create :: String -> SuperX
-- create can now be implemented
instance X SuperX where
-- a lot of boilerplate code ...
但是,样板代码建议可以做得更好。这真的是最好的方法吗?
答案 0 :(得分:2)
这取决于您需要如何处理。
如果以后的处理对它们进行A
,B
或C
的处理{em> ,则不关心它们,只是它实现了{ {1}} ...
X
然后您可以使用延续传递:
restOfProgram :: X a => a -> ThingIWantToCompute
或存在数据包装器:
parseABC :: (X a => a -> r) -> String -> Maybe r
parseABC f "A" = Just (f A)
parseABC f ('B':xs) = Just (f (B xs))
parseABC f ('C':xs) = Just (f (C (read xs)))
parseABC _ _ = Nothing
如果以后的处理对于data SomeX where
SomeX :: X t => t -> SomeX
parseABC :: String -> Maybe SomeX
parseABC "A" = Just (SomeX A)
parseABC ('B':xs) = Just (SomeX (B xs))
parseABC ('C':xs) = Just (SomeX (C (read xs)))
parseABC _ _ = Nothing
restOfProgram' :: SomeX -> ThingIWantToCompute
restOfProgram' (SomeX t) = restOfProgram t
,A
或B
具有不同的路径,则您可能希望返回类似C
的求和类型。