通过枚举创建函数

时间:2011-06-06 01:35:59

标签: haskell algebraic-data-types

我刚开始学习Haskell。我认为我已经掌握了基础知识,但我想确保我实际上也强迫自己在功能上思考。

data Dir = Right | Left | Front | Back | Up | Down deriving (Show, Eq, Enum)
inv Right = Left
inv Front = Back
inv Up = Down

无论如何,我要做的就是创建一个函数来映射每个“Dir”和它的对面/ inv。我知道我可以轻松地继续这3行,但我不禁想知道是否有更好的方法。我尝试添加:

inv a = b where inv b = a

但显然你不能这样做。所以我的问题是:是否有一种方法可以生成其余的反转或者更好的方法来创建这个函数?

非常感谢。

5 个答案:

答案 0 :(得分:18)

如果UpDown之间的配对等等是一个重要特征,那么这些知识应该反映在类型中。

data Axis = UpDown | LeftRight | FrontBack
data Sign = Positive | Negative
data Dir = Dir Axis Sign

inv现在很容易。

答案 1 :(得分:2)

对于与此功能相对应的索引,您是否有封闭式解决方案?如果是,是的,您可以使用Enum派生来简化事情。例如,

import Prelude hiding (Either(..))

data Dir = Right
         | Front
         | Up

         | Left
         | Back
         | Down
     deriving (Show, Eq, Ord, Enum)

inv :: Dir -> Dir
inv x = toEnum ((3 + fromEnum x) `mod` 6)

注意,这个依赖于构造函数的排序

*Main> inv Left
Right
*Main> inv Right
Left
*Main> inv Back
Front
*Main> inv Up
Down

这非常像C,利用构造函数的顺序,并且是非Haskelly。妥协是使用更多类型,来定义构造函数及其镜像之间的映射,避免使用算术。

import Prelude hiding (Either(..))

data Dir = A NormalDir
         | B MirrorDir
     deriving Show

data NormalDir = Right | Front | Up
     deriving (Show, Eq, Ord, Enum)

data MirrorDir = Left  | Back  | Down     
     deriving (Show, Eq, Ord, Enum)

inv :: Dir -> Dir
inv (A n) = B (toEnum (fromEnum n))
inv (B n) = A (toEnum (fromEnum n))

E.g。

*Main> inv (A Right)
B Left
*Main> inv (B Down)
A Up

所以至少我们不必做算术。并且类型区分镜子案例。但是,这非常非Haskelly。枚举案件绝对没问题!其他人必须在某个时候阅读你的代码...

答案 2 :(得分:2)

pairs = ps ++ map swap ps where
   ps = [(Right, Left), (Front, Back), (Up, Down)]
   swap (a, b) = (b, a)

inv a = fromJust $ lookup a pairs    

<强> [编辑]

或者这个怎​​么样?

inv a = head $ delete a $ head $ dropWhile (a `notElem`)
        [[Right,Left],[Front,Back],[Up,Down]]

答案 3 :(得分:1)

我不认为我会推荐这个,但我想到的简单答案就是添加这个:

inv x = fromJust $ find ((==x) . inv) [Right, Front, Up]

我无法抗拒调整Landei的答案以适应我的风格;这是一个类似的,稍微更推荐的解决方案,不需要其他定义:

inv a = fromJust $ do pair <- find (a `elem`) invList
                      find (/= a) pair
  where invList = [[Right, Left], [Up, Down], [Front, Back]]

它使用了Maybe monad。

答案 4 :(得分:1)

很高兴知道Enum从零开始。

助记符:fmap fromEnum [False,True] == [0,1]


import Data.Bits(xor)

-- Enum:       0   1          2   3       4   5
data Dir = Right | Left | Front | Back | Up | Down
           deriving (Read,Show,Eq,Ord,Enum,Bounded)

inv :: Dir -> Dir
inv = toEnum . xor 1 . fromEnum