首先,您描述的内容和Either Int String
签名似乎不匹配 - 我将尝试您首先描述的内容(通过输入类型选择输出类型):
你可以做一些与我认为你正在尝试的类型系列非常相似的事情:
{-# LANGUAGE TypeFamilies #-}
module SO where
data Foo = One | Two | Three deriving (Show, Read)
data Bar = This | That | TheOther deriving (Show, Read)
class PolyMap k where
type To k :: *
polyMap :: k -> To k
instance PolyMap Foo where
type To Foo = Int
polyMap _ = 123
instance PolyMap Bar where
type To Bar = String
polyMap _ = "string"
例子:
λ> polyMap One
123
λ> polyMap That
"string"
一些解释
我认为你想要的是类型映射/函数(没有typeOf
开箱即用的运行时检查,这会给你一些很好的类型检查支持)并且基本上有两种方法可以做到这一点(我我知道)
两者都为您(除其他外)提供了某种表达方式的方法:看看我是否得到类型 AI 可以说出一些相关的 B 类型必须是什么(Foo -> Int
和Bar -> String
)
这是一个很深的话题(边界依赖类型;)),但我认为有类的类型家族并不难理解。
我使用的想法是拥有PolyMap
提供polyMap
函数的类(您可以将其命名为任何您想要的 - doSomething
,无论如何),并且输出类型取决于使用To k
映射的输入类型,如实例中所述的Int
forFoo
和String
for -Bar
声明。
您签名的另一个更容易:
doSomething :: Either Foo Bar -> Either Int String
doSomething (Left _) = Left 123
doSomething (Right _) = Right "string"
例子:
λ> doSomething (Left One)
Left 123
λ> doSomething (Right That)
Right "string"