3

Haskell 中是否有可能拥有一个可以采用多态类型并返回多态类型的函数?

例如,我想要一个接受值的函数,如果值是类型Foo,则返回 Int,如果是类型,则返回 StringBar

data Foo = One | Two | Three deriving (Show, Read)
data Bar = This | That | TheOther deriving (Show, Read)

doSomething :: Either Foo Bar -> Either Int String
doSomething var = if (typeOf var) == Int then 123 else "string"

这样的事情可能吗?如果不是,基于类型路由到另一个函数的最佳实践是什么?

4

2 回答 2

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 -> IntBar -> String

这是一个很深的话题(边界依赖类型;)),但我认为有类的类型家族并不难理解。

我使用的想法是拥有PolyMap提供polyMap函数的类(您可以将其命名为任何您想要的 - doSomething,无论如何),并且输出类型取决于使用To k映射的输入类型,如实例中所述的IntforFooStringfor -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"
于 2015-11-25T06:40:09.123 回答
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。我不认为类型族提供了一种很好的建模方式。

于 2015-11-25T06:41:10.487 回答