gpt4 book ai didi

数据类型上的 Haskell toEnum 引发范围异常

转载 作者:行者123 更新时间:2023-12-04 05:48:19 25 4
gpt4 key购买 nike

我正在尝试为以下类型编写一个 Enum 实例:

-- Type declarations:

-- Octave
data Octave =
O1 | O2 | O3
deriving (Show, Read, Eq, Ord, Bounded, Enum)

-- Note
data Note =
A | B | C | D | E | F
deriving (Show, Read, Eq, Ord, Bounded, Enum)

-- Pitch
data Pitch = Pitch Octave Note
deriving (Show, Eq, Ord)

-- Why doesn't this work?
instance Enum Pitch where
fromEnum (Pitch o n) = (fromEnum o)*6 + (fromEnum n)
toEnum x = (Pitch o n)
where
o = toEnum (x `div` 6)
n = toEnum (x `mod` 6)

这适用于:
[(Pitch O1 A) .. (Pitch O3 F)]

但失败:
[(Pitch O1 A) .. ]

出现错误:
*** Exception: toEnum{Octave}: tag (3) is outside of enumeration's range (0,2)

我理解错误。
我的问题是:
如何正确编写 Enum 实例来执行此枚举?
可能吗?
最重要的是:这是好的做法吗?

最佳答案

你的问题是 Pitch是隐式有界的——也就是说,它有一个最小和最大的元素——但你没有在你的代码中反射(reflect)这种有界性。编码

[Pitch O1 A ..]

脱糖
enumFrom (Pitch O1 A)

保留 succ生成的值直到它 succ小号 Pitch O3 F并炸毁。它怎么会知道它应该停在那里?

From the Prelude documentation :

For any type that is an instance of class Bounded as well as Enum, the following should hold:

  • enumFrom and enumFromThen should be defined with an implicit bound, thus:

    enumFrom     x   = enumFromTo     x maxBound
    enumFromThen x y = enumFromThenTo x y bound
    where
    bound | fromEnum y >= fromEnum x = maxBound
    | otherwise = minBound


因此,要解决此问题,只需添加
instance Bounded Pitch where
minBound = Pitch minBound minBound
maxBound = Pitch maxBound maxBound

然后添加文档中的代码:
instance Enum Pitch where
-- ...
enumFrom x = enumFromTo x maxBound
enumFromThen x y = enumFromThenTo x y bound
where
bound | fromEnum y >= fromEnum x = maxBound
| otherwise = minBound

现在 [Pitch O1 A ..] 将在最后停止:
λ> [Pitch O1 A ..]
[Pitch O1 A,Pitch O1 B,Pitch O1 C,Pitch O1 D,Pitch O1 E,Pitch O1 F,Pitch O2 A,Pitch O2 B,Pitch O2 C,Pitch O2 D,Pitch O2 E,Pitch O2 F,Pitch O3 A,Pitch O3 B,Pitch O3 C,Pitch O3 D,Pitch O3 E,Pitch O3 F]

旁注:您可以替换对 div 的单独调用和 mod在一次调用 divMod 时进行模式匹配: x `divMod` y == (x `div` y, x `mod` y) . (对于像这样的严格正数,我相信我听说 quotRem 可能是更好的选择; quotrem 类似于 divmod ,但与符号相关的行为不同。 ) 此外,您可以替换您的 61 + (fromEnum (maxBound :: Note))以免不小心弄错号码。

关于数据类型上的 Haskell toEnum 引发范围异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32151954/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com