我不能在Char中添加数字;以下将无法编译'a' + 1。但是,['a'..'z']成功创建了一个字符串,其中每个字符值都递增。是否有可以增加Char的特殊功能?

我知道我可以做chr (ord c + 1)
['a'..'z']或基础enumFromTo函数如何增加结果String中的字符?

最佳答案

是的,有一个特殊的函数可以添加到Char中,该函数来自与Enum相同的enumFromTo类,即succ。请注意,它是不完整的:succ maxBound是未定义的,因此在应用succ之前请注意检查字符的值。 succ确实与\c -> chr (ord c + 1)相同,您可以使用universe包进行验证:

> let avoidMaxBound f x = if x == maxBound then Nothing else Just (f x)
> avoidMaxBound succ == avoidMaxBound (\c -> chr (ord c + 1))
True

实际上,implementation of succ in GHC与您建议的功能非常接近:
instance  Enum Char  where
    succ (C# c#)
       | isTrue# (ord# c# /=# 0x10FFFF#) = C# (chr# (ord# c# +# 1#))
       | otherwise             = error ("Prelude.Enum.Char.succ: bad argument")

但是,在GHC中的succ的实现中未使用enumFromTo:
instance  Enum Char  where
    {-# INLINE enumFromTo #-}
    enumFromTo (C# x) (C# y) = eftChar (ord# x) (ord# y)
{-# RULES
"eftChar"       [~1] forall x y.        eftChar x y       = build (\c n -> eftCharFB c n x y)
#-}

-- We can do better than for Ints because we don't
-- have hassles about arithmetic overflow at maxBound
{-# INLINE [0] eftCharFB #-}
eftCharFB :: (Char -> a -> a) -> a -> Int# -> Int# -> a
eftCharFB c n x0 y = go x0
                 where
                    go x | isTrue# (x ># y) = n
                         | otherwise        = C# (chr# x) `c` go (x +# 1#)

{-# NOINLINE [1] eftChar #-}
eftChar :: Int# -> Int# -> String
eftChar x y | isTrue# (x ># y ) = []
            | otherwise         = C# (chr# x) : eftChar (x +# 1#) y

如果您可以斜视过去主要出于效率原因而存在的麻烦,则可以看到eftChar本质上是使用succ,而是它的内联版本,而不是对succ的实际调用(此处是为了避免将BOXt和BOX重新装箱)操纵)。

关于haskell - enumFromTo如何工作?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31754011/

10-11 18:58