Haskell 在枚举上创建函数

Haskell 在枚举上创建函数,haskell,algebraic-data-types,Haskell,Algebraic Data Types,我刚开始学哈斯克尔。我想我已经掌握了基本知识,但我想确保我实际上也在强迫自己从功能上思考 data Dir = Right | Left | Front | Back | Up | Down deriving (Show, Eq, Enum) inv Right = Left inv Front = Back inv Up = Down 无论如何,我尝试做的jist是创建一个函数,在每个“Dir”和它的对立面/inv之间映射。我知道我可以很容易地继续这3行,但我忍不住想知道是否有更好的方法。我

我刚开始学哈斯克尔。我想我已经掌握了基本知识,但我想确保我实际上也在强迫自己从功能上思考

data Dir = Right | Left | Front | Back | Up | Down deriving (Show, Eq, Enum)
inv Right = Left
inv Front = Back
inv Up = Down
无论如何,我尝试做的jist是创建一个函数,在每个“Dir”和它的对立面/inv之间映射。我知道我可以很容易地继续这3行,但我忍不住想知道是否有更好的方法。我试着加上:

inv a = b where inv b = a
但显然你不能这么做。所以我的问题是:是否有一种方法可以生成其余的逆函数,或者有一种更好的方法来创建这个函数


非常感谢。

对于与此函数对应的索引,您是否有一个封闭形式的解决方案?如果是这样,可以使用
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)
注意,这取决于构造函数的顺序

这是非常类似C的,利用构造函数的顺序,并且是非Haskell的。一种折衷方法是使用更多类型,定义构造函数与其镜像之间的映射,避免使用算术

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))
例如


所以至少我们不用做算术。镜壳的类型也不同。然而,这是非常不明智的。列举这些案例是绝对正确的!其他人将不得不在某个时候阅读您的代码…

如果
向上
向下
等之间的配对是一个重要的功能,那么这种知识可能应该反映在类型中

data Axis = UpDown | LeftRight | FrontBack
data Sign = Positive | Negative
data Dir = Dir Axis Sign
inv
现在很简单

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]]

我不认为我会推荐这一点,但在我脑海中,简单的答案是添加以下内容:

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

我忍不住调整兰黛的答案以符合我的风格;下面是一个类似的、略为推荐的解决方案,它不需要其他定义:

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

inv a=fromJust$do pair很高兴知道,
Enum
从零开始

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



那更好。准确捕捉类型中的核心概念(维度和方向)。有意义。在“符号”上求“inv正”的逆比在所有“Dir”上求“inv右”的逆要好。所以,唯一一个干净地进行“反转”的方法就是把你正在反转的东西变小…@rcb451,你没有抓住要点。
Sign
具有较少的数据构造函数这一事实是偶然的(尽管肯定是有益的)。关键的观察结果是,
之间的密切关系应该反映在它们的类型中,同样地,(例如)
之间的距离关系。类型系统是用来帮助处理不变量的:有了更多的类型,你可以表达更精确的不变量。嗯?缺陷这并不比说明
inv x=inv x
更好。我的意思是在他已经为
inv Right
inv Front
inv Up
编写的定义之后添加这一点。
inv x = fromJust $ find ((==x) . inv) [Right, Front, Up]
inv a = fromJust $ do pair <- find (a `elem`) invList
                      find (/= a) pair
  where invList = [[Right, Left], [Up, Down], [Front, Back]]
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