一般转换类型

Oll*_*ers 5 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
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)

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


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

C. *_*ann 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)
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)是在上下文中吗?这使得反向映射可以工作,但并不将其限制为仅反向特定定义的实例。