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