haskell 多态类型函数

haskell polymorphic type functions

在 Haskell 中是否可以有一个函数可以采用多态类型并且 return 可以采用多态类型?

例如,我想要一个接受值的函数,如果值是 Foo 类型,则 return 是一个 Int,如果是 Bar 类型,则是一个 String

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"

这样的事情可能吗?如果不是,根据类型路由到另一个函数的最佳做法是什么?

首先,您描述的内容和 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"

一些解释

我想你想要的是type-mappings/functions(typeOf没有运行时检查,开箱即用,这会给你一些很好的类型检查支持)和基本上有两种方法(我知道)

两者都为您(以及其他人)提供了一些表达方式:看看我是否得到类型 A 我可以说出某些关联类型 B 必须是什么(Foo -> IntBar -> String

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

我使用的想法是让 class PolyMap 提供 polyMap 功能(您可以将其命名为您想要的任何名称 - doSomething,随便什么)并且输出类型取决于使用 To k 映射的输入类型,如实例声明中所述,Int 对应 FooString 对应 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"

您可以将 doSomething 放入以域和共域类型为键的类型类中,具有从域到共域的功能依赖性:

{-# 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。我不认为类型族提供了一种很好的建模方式。