enumFromTo如何工作? [英] How does enumFromTo work?
问题描述
我无法将数字添加到 Char
;以下将无法编译'a'+ 1
。但是, ['a'..'z']
成功地创建了一个字符串,其中每个字符值都被增加。是否有一个特殊的函数可以增加 Char
?
我知道我可以做 chr(ord c + 1)
。
['a'..'z']
或底层的 enumFromTo
函数递增结果中的字符 String
?
Char
,来自同一个 Enum
类 enumFromTo
来自 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屋!