在Haskell中是否可以使用一个可以采用多态类型并返回多态类型的函数?
例如,我想要一个接受值的函数,如果值为mailchimp
,则返回一个Int,如果类型为Foo
,则返回一个字符串
Bar
这样的事情可能吗?如果没有,基于类型路由到另一个函数的最佳实践是什么?
答案 0 :(得分:5)
首先你描述的内容和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
)
这是一个很深层次的主题(borderline dependent-types;))但我认为带类的类型系列并不难理解。
我使用的想法是让类PolyMap
提供polyMap
函数(你可以将它命名为你想要的任何东西 - doSomething
,无论如何)并且输出类型取决于输入类型使用To k
映射,Int
为Foo
,String
为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"
答案 1 :(得分:3)
您可以将doSomething
置于以域和codomain类型为键的类型类中,并具有从域到codomain的功能依赖性:
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-} -- if one of your `to` really is `String`
class DoSomething from to | from -> to where
doSomething :: from -> to
instance DoSomething Foo Int where -- ...
instance DoSomething Bar String where -- ...
与基于类型族的解决方案相比,这样做的好处是如果codomain也唯一地确定了域,则可以添加另一个函数依赖项to -> from
。我不认为类型系列提供了一种很好的建模方法。