一般转换类型

时间:2010-10-24 02:02:26

标签: haskell typeclass

我想看看是否可以使用类型类将一个事物转换为另一个事物并从[(a,b)]的映射中再次返回。

这个例子应该说明我想做的事情:

data XX = One | Two | Three deriving (Show, Eq)
data YY = Eno | Owt | Eerht deriving (Show, Eq)

instance Convert XX YY where
   mapping = [(One, Eno), (Two, Owt), (Three, Eerht)]

-- // How can I make this work?:
main = do print $ (convert One :: YY) -- Want to output: Eno
          print $ (convert Owt :: XX) -- Want to output: Two

这是我努力做到这一点:

{-# LANGUAGE MultiParamTypeClasses #-}    
import Data.Maybe(fromJust)

lk = flip lookup
flipPair = uncurry $ flip (,)

class (Eq a, Eq b) => Convert a b where

   mapping :: [(a, b)]
   mapping = error "No mapping defined"

   convert :: a -> b
   convert = fromJust . lk mapping

-- // This won't work:
instance (Convert a b) => Convert b a where
   convert = fromJust . lk (map flipPair mapping)

很容易做到这一点,为转换定义两个实例,但是我只想在第一个例子中声明一个。知道怎么做这个吗?


编辑:我认为可行,这可以在没有重叠实例的情况下完成任何其他讨厌的扩展吗?

1 个答案:

答案 0 :(得分:4)

我,呃......我几乎不想提出这个建议,因为这样做有点可怕,但是......你的代码不能正常工作吗?

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE OverlappingInstances #-}
import Data.Maybe(fromJust)

lk x = flip lookup x
flipPair = uncurry $ flip (,)

class (Eq a, Eq b) => Convert a b where
   mapping :: [(a, b)]
   mapping = error "No mapping defined"
   convert :: a -> b
   convert = fromJust . lk mapping

instance (Convert a b) => Convert b a where
   convert = fromJust . lk (map flipPair mapping)

data XX = One | Two | Three deriving (Show, Eq)
data YY = Eno | Owt | Eerht deriving (Show, Eq)

instance Convert XX YY where
   mapping = [(One, Eno), (Two, Owt), (Three, Eerht)]

main = do print $ (convert One :: YY)
          print $ (convert Owt :: XX)

[1 of 1] Compiling Main             ( GeneralConversion.hs, interpreted )
Ok, modules loaded: Main.
*Main> main
Eno
Two
*Main> 

我不确定这样的类型类是多么有用,所有关于可疑扩展的标准免责声明都适用,但这似乎有用。现在,如果你想做任何事情 fancier ......比如Convert a a(Convert a b, Convert b c) => Convert a c ......事情可能会变得尴尬。


我想我不妨留下一些关于为什么我怀疑这种效用的想法:

  • 为了使用转换,必须明确知道这两种类型;同样,转换的存在取决于两种类型。与诸如fromIntegral之类的内容相比,这限制了类用于编写非常通用代码的有用性。

  • 使用error处理丢失的转换,结合上述内容,意味着使用convert的任何涉嫌通用函数都将成为等待发生的运行时错误的焦点。< / p>

  • 最重要的是,用于反向映射的通用实例实际上是通用实例,只是被重叠的,更具体的实例隐藏。上下文中的(Convert a b)?这使得反向映射可以工作,但不会将其限制为只反转特定定义的实例。