enumFromTo如何工作? [英] How does enumFromTo work?

查看:97
本文介绍了enumFromTo如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法将数字添加到 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

事实上,执行 GHC中的> succ 与您所建议的函数非常接近:

  instance Enum Char,其中
succ(C#c#)
| isTrue#(ord#c#/ =#0x10FFFF#)= C#(chr#(ord#c#+#1#))
|否则=错误(Prelude.Enum.Char.succ:错误的参数)

然而,<$在GHC中执行 enumFromTo 时不使用c $ c> succ

 instance Enum Char where 
{ - #INLINE enumFromTo# - }
enumFromTo(C#x)(C#y)= eftChar(ord#x)(ord#y )
{ - #RULES
eftChar[〜1] forall x y。 eftChar xy = build(\ cn - > eftCharFB cnxy)
# - }

- 我们可以做得比Ints更好,因为我们没有
- 拥有关于在maxBound处的算术溢出的麻烦
{ - #INLINE [0] eftCharFB# - }
eftCharFB ::(Char - > a - > a) - > a - > Int# - > Int# - > a
eftCharFB c n x0 y = go x0
其中
go x | isTrue#(x>#y)= n
|否则= C#(chr#x)`c` go(x +#1#)

{ - #NOINLINE [1] eftChar# - }
eftChar :: Int# - > Int# - >字符串
eftChar x y | isTrue#(x>#y)= []
|否则= C#(chr#x):eftChar(x +#1#)y

如果可以斜视过去主要出于效率原因而存在的糟糕情况,您可以看到 eftChar 基本上使用 succ ,但内联它的版本,而不是实际调用 succ (这里,为了避免装箱和重新装箱 Char 被操纵)。


I cannot add a number to a Char; the following will fail to compile 'a' + 1. But yet, ['a'..'z'] successfully creates a string in which each of the character value is incremented. Is there a special function that can increment a Char?

I know that I can do chr (ord c + 1).

How does the ['a'..'z'] or the underlying enumFromTo function increment the characters in the resulting String?

解决方案

Yes, there is a special function that can add to a Char, from the same Enum class that enumFromTo is from, named succ. Beware that it is partial: succ maxBound is undefined, so take care to check the value of the character before you apply succ. succ is indeed the same as \c -> chr (ord c + 1), as you can verify with the universe package:

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

In fact the implementation of succ in GHC is quite close to the function you suggested:

instance  Enum Char  where
    succ (C# c#)
       | isTrue# (ord# c# /=# 0x10FFFF#) = C# (chr# (ord# c# +# 1#))
       | otherwise             = error ("Prelude.Enum.Char.succ: bad argument")

However, succ is not used in the implementation of enumFromTo in GHC:

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

If you can squint past the nastiness that exists primarily for efficiency reasons, you can see that eftChar is essentially using succ, but an inlined version of it rather than an actual call to succ (here, to avoid boxing and re-boxing the Char being manipulated).

这篇关于enumFromTo如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆