如何在haskell中反转整数?

时间:2013-11-01 10:49:39

标签: haskell integer int

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

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

我需要将Integer输入数字反转,如下例所示。

示例:

> reverseInt 1989
9891

3 个答案:

答案 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')

它也适用于负数。

EDIT2:

正如注释中所指出的,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之间的选择

  • 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

<强> 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