我想看看是否可以使用类型类将一个事物转换为另一个事物并从[(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)
很容易做到这一点,为转换定义两个实例,但是我只想在第一个例子中声明一个。知道怎么做这个吗?
编辑:我认为可行,这可以在没有重叠实例的情况下完成任何其他讨厌的扩展吗?
答案 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)
?这使得反向映射可以工作,但不会将其限制为只反转特定定义的实例。