我想看看是否有可能有一个类型类将一个东西转换成另一个东西,然后再从映射中转换回来[(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
Run Code Online (Sandbox Code Playgroud)
这是我努力做到这一点:
{-# 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)
Run Code Online (Sandbox Code Playgroud)
很容易做到这一点,为转换定义两个实例,但是我只想在第一个例子中声明一个.知道怎么做这个吗?
编辑:我认为可行,这可以在没有重叠实例的情况下完成任何其他讨厌的扩展吗?
我,呃...我几乎不想建议这个,因为这样做有点可怕,但是...你的代码不按原样工作吗?
{-# 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)
Run Code Online (Sandbox Code Playgroud)
和:
[1 of 1] Compiling Main ( GeneralConversion.hs, interpreted )
Ok, modules loaded: Main.
*Main> main
Eno
Two
*Main>
Run Code Online (Sandbox Code Playgroud)
我不确定这样的类型类有多大用处,并且所有关于可疑扩展的标准免责声明都适用,但这似乎很有效。现在,如果你想做一些更奇特的事情……比如Convert a a或者(Convert a b, Convert b c) => Convert a c……事情可能会变得尴尬。
我想我不妨留下一些关于为什么我怀疑这个实用性的想法:
为了使用转换,必须明确知道这两种类型;同样,转换的存在取决于这两种类型。与诸如fromIntegral.
使用error来处理丢失的转换,与上述相结合,意味着任何所谓的泛型函数使用都convert将成为等待发生的运行时错误的深渊。
最重要的是,用于反向映射的通用实例实际上是通用实例,只是被重叠的更具体的实例隐藏。那(Convert a b)是在上下文中吗?这使得反向映射可以工作,但并不将其限制为仅反向特定定义的实例。