Function 用于在代数数据类型之间转换的Haskell多态函数
我有两个haskell函数,它们在两种代数数据类型之间转换Function 用于在代数数据类型之间转换的Haskell多态函数,function,haskell,types,Function,Haskell,Types,我有两个haskell函数,它们在两种代数数据类型之间转换 data Ab = A | B data Cd = C | D fromAb :: Ab -> Cd fromAb A = C fromAb B = D toAb :: Cd -> Ab toAb C = A toAb D = B 但我想做一个多变形函数,它同时接受代数数据类型和它们之间的转换 foo A = C foo B = D foo C = A foo D = B 但是Haskell从“fooa=C”推断出函
data Ab = A | B
data Cd = C | D
fromAb :: Ab -> Cd
fromAb A = C
fromAb B = D
toAb :: Cd -> Ab
toAb C = A
toAb D = B
但我想做一个多变形函数,它同时接受代数数据类型和它们之间的转换
foo A = C
foo B = D
foo C = A
foo D = B
但是Haskell从“fooa=C”推断出函数是
foo :: Ab -> Cd
我试图创建一个类的数据类型实例来创建foo polymorph,但没有成功
class Abcd a
instance Abcd Ab
instance Abcd Cd
foo :: Abcd a => a -> Ab
有什么想法吗?这对于
TypeFamilies
来说是很自然的。您可以定义类型级别的函数
type family Converted a
type instance Converted Ab = Cd
type instance Converted Cd = Ab
那么你的签名就变成了
foo :: a -> Converted a
如果您只是在摆弄类型,那么您就可以这样做了,但是由于您希望在值级别上有不同的行为(从AC
返回A,等等),我们实际上需要在新类型类的实例中分布我们的案例:
class Convertable a where
foo :: a -> Converted a
instance Convertable Ab where
foo A = C
foo B = D
instance Convertable Cd where
foo C = A
foo D = B
()
最后,如果使用最近的GHC,可以考虑将<代码>转换为一个封闭类型的同义词族,或者通过在
foo::abo a=>a->Ab
,因为如果a~Ab
,那么函数应该返回一张Cd
,而不是Ab
做你想做的事有几种不同的方法。首先,要认识到,您试图表达的是一组常见的行为,而不是基于一个类型,而是基于两个类型之间的关系。这基本上就是多参数typeclass的用途(这可能是实现这一点的最简单方法)
编辑:请注意,我的答案与jberryman的完全相同,后者使用类型族。这就是我所说的“做你想做的事情的几种方法”的意思。另一种方法是使用扩展名
MultiParamTypeClasses
和函数依赖性
:
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
data Ab = A | B deriving (Show)
data Cd = C | D deriving (Show)
class Convert a b | a -> b where
convert :: a -> b
instance Convert Ab Cd where
convert A = C
convert B = D
instance Convert Cd Ab where
convert C = A
convert D = B
演示:
Fundeps可能是op想要的:
class Iso a b | a->b
,这将是解决此问题的传统方法(预类型族)。对于这种情况,实际上不需要Fundeps,因为to
使用两种类型的实例。这将阻止您向此“可转换”类型组添加新类型。抱歉,我的评论不太清楚。我的意思是,fundeps的类型推断会更好,要么a->b
(相当于TypeFamilies),要么a->b,b->a
。我相信,将写入一个
中是不明确的。不,你是对的,添加fundeps当然没有错,但它表达的属性可能是可取的,也可能是不可取的,这取决于应用程序。如果我们稍后添加data Ef
,我们没有理由不能通过声明适当的实例,使用在3种类型之间任意转换为。但是,如果我们使用fundep,这是不可能的,但是如果我们不需要这种灵活性,当然还有更简单的类型推断的额外好处。
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
data Ab = A | B deriving (Show)
data Cd = C | D deriving (Show)
class Convert a b | a -> b where
convert :: a -> b
instance Convert Ab Cd where
convert A = C
convert B = D
instance Convert Cd Ab where
convert C = A
convert D = B
λ> convert A
C
λ> convert B
D
λ> convert C
A
λ> convert D
B