有什么方法可以在haskell中定义一个环绕的枚举吗?

如何解决有什么方法可以在haskell中定义一个环绕的枚举吗?

| 考虑我正在设计一个大富翁游戏:
data Board = GO | A1 | CC1 | A2 | T1 | R1 | B1 | CH1 | B2 | B3 | 
  JAIL | C1 | U1 | C2 | C3 | R2 | D1 | CC2 | D2 | D3 | 
  FP | E1 | CH2 | E2 | E3 | R3 | F1 | F2 | U2 | F3 | 
  G2J | G1 | G2 | CC3 | G3 | R4 | CH3 | H1 | T2 | H2
  deriving (Show,Enum,Eq)
我想要:
succ H2 == GO
但反而:
*** Exception: succ{Board}: tried to take `succ\' of last tag in enumeration
是否存在用于表示环绕的枚举的类型类?     

解决方法

最简单的选择是使Board为
Bounded
的实例(也可以自动派生),并使用以下帮助函数:
next :: (Enum a,Bounded a) => a -> a
next = turn 1

prev :: (Enum a,Bounded a) => a -> a
prev = turn (-1)

turn :: (Enum a,Bounded a) => Int -> a -> a
turn n e = toEnum (add (fromEnum (maxBound `asTypeOf` e) + 1) (fromEnum e) n)
    where
      add mod x y = (x + y + mod) `rem` mod
使用示例:
> next H2
G0
> prev G0
H2
> next F1
F2
(灵感来自http://www.mail-archive.com/haskell-cafe@haskell.org/msg37258.html上的线程)。 如果您确实需要使用
succ
和ѭ7,,我不相信有关于ѭ8implementation的实现的法律,因此对于所有
x
都以
succ (succ x) /= x
为代表(即使多数情况下也是这样)。因此,您可以为您的类型编写一个自定义实现
Enum
,以实现所需的环绕效果:
instance Enum Board where
  toEnum 0 = G0
  toEnum 1 = A1
  ...
  toEnum 40 = H2
  toEnum x = toEnum (x `mod` 40)

  fromEnum G0 = 0
  fromEnum A1 = 1
  ...
  fromEnum H2 = 40
但是,实现起来非常繁琐。另外,使用循环定义
Enum
时,该类型也不应实现
Bounded
,因为这违反了有关
Bounded
的规则,即rule16ѭ会导致运行时错误。     ,一个比nanothief更简单的解决方案:
nextBoard :: Board -> Board
nextBoard H2 = GO
nextBoard t = succ t
我认为您不能直接将Enum用于所需的内容,但是此解决方案可以快速将其包装以形成所需的行为。     ,我知道这是一个古老的问题,但我只是遇到了这个问题,所以就这样解决了。
data SomeEnum = E0 | E1 | E2 | E3
               deriving (Enum,Bounded,Eq)

-- | a `succ` that wraps 
succB :: (Bounded a,Enum a,Eq a) => a -> a 
succB en | en == maxBound = minBound
         | otherwise = succ en

-- | a `pred` that wraps
predB :: (Bounded a,Eq a) => a -> a
predB en | en == minBound = maxBound
         | otherwise = pred en  
该解决方案既可以导出
Enum
Bounded
,又可以避免建议的滥用
pred
succ
。 偶然地,我发现
allSomeEnum = [minBound..maxBound] :: [SomeEnum] 
可能会有用。这需要
Bounded
。     ,有一种令人作呕的方法来定义高效的包装
Enum
实例,而无需手动进行任何操作。
{-# LANGUAGE MagicHash #-}

import GHC.Exts (Int (..),tagToEnum#,dataToTag# )

-- dataToTag# :: a -> Int#
-- tagToEnum# :: Int# -> a
现在你可以写
data Board = ... deriving (Eq,Ord,Bounded)

instance Enum Board where
  fromEnum a = I# (dataToTag# a)

  toEnum x | x < 0 || x > fromEnum (maxBound :: Board) =
    error \"Out of range\"
  toEnum (I# t) = tagToEnum# t
  succ x | x == maxBound = minBound
         | otherwise == toEnum (fromEnum x + 1)
  pred x ....
    ,使用
Eq
,您可以检查它是否是最后一个元素。
next :: (Eq a,Bounded a) => a -> a
next = bool minBound <$> succ <*> (/= maxBound)
    

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?