4

我需要有关如何Integer使用以下类型签名在 Haskell 中反转 a 的帮助:

reverseInt :: Integer -> Integer
reverseInt a = undefined -- help here

我需要Integer像下面的示例一样反转输入数字。

例子:

> reverseInt 1989
9891
4

3 回答 3

12
reverseInt :: Integer -> Integer
reverseInt = read . reverse . show

这不解决负数。如果你需要反转负数,你可以简单地使用

reverseInt :: Integer -> Integer
reverseInt x = (*) (signum x) . read . reverse . show . abs  $ x
于 2013-11-01T10:51:14.920 回答
11

一种避免使用的方法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')

它也适用于负数。

编辑2:

正如评论中所指出的,可以对 aux 函数进行一些优化,省略元组,这可以防止编译器评估 whnf(弱头范式),即如果编译器看到一个表达式,它会尽可能少地评估它,直到它看到了第一个构造函数。在 aux 的情况下,它是元组构造函数(,)。使用 ghci + 可以实现对 whnf 的良好感觉:sprint,请参阅 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我的版本之间进行选择

  • Int 版本大约需要 200 ns
  • 整数版本----" ----- 600 ns

其他版本涉及showread花费了更长的时间,但所有版本都在 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

基准.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 ]]
于 2013-11-01T12:34:57.380 回答
5

将数字转换为字符串,将其还原,然后将反转的字符串转换回数字。Integer值可以是负数,因此请注意前导-

reverseInt :: Integer -> Integer
reverseInt x | x < 0     = 0 - (read . reverse . tail . show $ x)
             | otherwise = read . reverse . show $ x
于 2013-11-01T10:57:12.983 回答