我需要有关如何使用以下类型签名来反转Haskell中的Integer
的帮助:
reverseInt :: Integer -> Integer
reverseInt a = undefined -- help here
我需要将Integer
输入数字反转,如下例所示。
示例:
> reverseInt 1989
9891
答案 0 :(得分:11)
reverseInt :: Integer -> Integer
reverseInt = read . reverse . show
这不涉及负数。如果你需要反转负数,你可以简单地使用
reverseInt :: Integer -> Integer
reverseInt x = (*) (signum x) . read . reverse . show . abs $ x
答案 1 :(得分:10)
避免使用show
的一种方法就是这个
reverseInt :: Integer -> Integer
reverseInt n = aux (n,0)
where aux (0,y) = y
aux (x,y) = let (x',y') = x `quotRem` 10
in aux (x',10*y+y')
它也适用于负数。
正如注释中所指出的,aux函数可以稍微优化一下,省略元组,这可以防止编译器评估为whnf(弱头普通形式),即如果编译器看到一个表达式,它只评估它必要的,直到它看到第一个构造函数。在aux的情况下,它是元组构造函数(,)
。使用ghci + :sprint
可以获得对whnf的良好感觉,请参阅simon marlow的书(http://chimera.labs.oreilly.com/books/1230000000929/ch02.html)。
reverseInt :: Int -> Int
reverseInt n = aux n 0
where aux 0 y = y
aux x y = let (x',y') = x `quotRem` 10
in aux x' (10*y+y')
正如@FrerichRaabe指出的那样,这完成了所需的任务,但我承认,理解它比 - read . reverse . show
更棘手。因此,我将在一个示例中解释aux
的作用:
aux 1234 0 => 1234 `quotRem` 10 => (123,4) => x'= 123, y'= 4
=> aux 123 (0*10+4) => aux 123 4
aux 123 4 => 123 `quotRem` 10 => (12,3) => x'= 12, y'= 3
=> aux 12 (4*10+3) => aux 12 43
aux 12 43 => 12 `quotRem` 10 => (1,2) => x'= 1, y'= 2
=> aux 1 (43*10+2) => aux 1 432
aux 1 432 => 1 `quotRem` 10 => (0,1) => x'= 0, y'= 1
=> aux 0 (432*10+1) => aux 0 4321
aux 0 4321 => 4321
我决定是否我的假设包括show
是个坏主意。
简短版是!
长版
我把所有版本都放在一个文件中,并添加了我的方法的严格版本,看看,如果累加器中的非严格部分很重要(事实证明:不是真的)。重要的是我的机器上的Int
(Int64)和我的版本中的Integer
之间的选择
涉及show
和read
的其他版本需要更长时间,
但所有这些都是6000 ns左右 - 这是30分钟的因素。 10与我的版本相比。
有关详细信息,您可能需要查看criterion
库生成的报告(谢谢Bryan O'Sullivan !!),保存下面的文件并输入shell。
$ ghc -O --make benchmarks.hs
$ ./benchmarks -o Report.html
<强> RevInt.hs 强>
{-# LANGUAGE BangPatterns #-}
module RevInt where
epsilon_fast :: Int-> Int
epsilon_fast n = aux n 0
where aux :: Int -> Int -> Int
aux 0 !y = y
aux x !y = let (x',y') = x `quotRem` 10
in aux x' (10*y+y')
epsilon_Integer :: Integer -> Integer
epsilon_Integer n = aux (n,0)
where aux (0,y) = y
aux (x,y) = let (x',y') = x `quotRem` 10
in aux (x',10*y+y')
epsilon_rInt :: Int-> Int
epsilon_rInt n = aux (n,0)
where aux (0,y) = y
aux (x,y) = let (x',y') = x `quotRem` 10
in aux (x',10*y+y')
epsilon_Integer' :: Integer -> Integer
epsilon_Integer' n = aux (n,0)
where aux (0,y) = y
aux (x,y) = let (x',y') = x `quotRem` 10
!z = 10*y+y'
in aux (x',z)
epsilon_rInt' :: Int-> Int
epsilon_rInt' n = aux (n,0)
where aux (0,y) = y
aux (x,y) = let (x',y') = x `quotRem` 10
!z = 10*y+y'
in aux (x',z)
fRaabe_Integer :: Integer -> Integer
fRaabe_Integer x | x < 0 = 0 - (read . reverse . tail . show $ x)
| otherwise = read . reverse . show $ x
fRaabe_Int :: Int -> Int
fRaabe_Int x | x < 0 = 0 - (read . reverse . tail . show $ x)
| otherwise = read . reverse . show $ x
zeta_Int :: Int -> Int
zeta_Int x = (*) (signum x) . read . reverse . show . abs $ x
zeta_Integer :: Integer -> Integer
zeta_Integer x = (*) (signum x) . read . reverse . show . abs $ x
<强> benchmarks.hs 强>
import Criterion.Main
import RevInt
main :: IO ()
main = defaultMain
[bgroup "epsilon_fast" [ bench "123456789" $ whnf epsilon_fast 123456789 ,
bench "987654321" $ whnf epsilon_fast 987654321 ]
,bgroup "epsilon_Integer" [ bench "123456789" $ whnf epsilon_Integer 123456789 ,
bench "987654321" $ whnf epsilon_Integer 987654321 ]
,bgroup "epsilon_rInt" [ bench "123456789" $ whnf epsilon_rInt 123456789 ,
bench "987654321" $ whnf epsilon_rInt 987654321 ]
,bgroup "epsilon_Integer'"[ bench "123456789" $ whnf epsilon_Integer' 123456789 ,
bench "987654321" $ whnf epsilon_Integer' 987654321 ]
,bgroup "epsilon_rInt'" [ bench "123456789" $ whnf epsilon_rInt' 123456789 ,
bench "987654321" $ whnf epsilon_rInt' 987654321 ]
,bgroup "fRaabe_Int" [ bench "123456789" $ whnf fRaabe_Int 123456789 ,
bench "987654321" $ whnf fRaabe_Int 987654321 ]
,bgroup "fRaabe_Integer" [ bench "123456789" $ whnf fRaabe_Integer 123456789 ,
bench "987654321" $ whnf fRaabe_Integer 987654321 ]
,bgroup "zeta_Int" [ bench "123456789" $ whnf zeta_Int 123456789 ,
bench "987654321" $ whnf zeta_Int 987654321 ]
,bgroup "zeta_Integer" [ bench "123456789" $ whnf zeta_Integer 123456789 ,
bench "987654321" $ whnf zeta_Integer 987654321 ]]
答案 2 :(得分:4)
将数字转换为字符串,将其还原,然后将反转的字符串转换回数字。 Integer
值可能为负值,因此需要处理前导-
:
reverseInt :: Integer -> Integer
reverseInt x | x < 0 = 0 - (read . reverse . tail . show $ x)
| otherwise = read . reverse . show $ x