如何在Haskell中获得大数字的总和?

Tim*_*Tim 13 haskell

我是一名C++程序员,正在尝试自学Haskell,并且它证明了把握使用函数作为一种循环的基础知识的挑战.我有一个很大的数字,50!,我需要添加其数字的总和.这是一个相对简单的C++循环,但我想学习如何在Haskell中完成它.

我已经阅读了一些入门指南,能够获得50分!同

sum50fac.hs ::

fac 0 = 1
fac n = n * fac (n-1)
x = fac 50
main = print x
Run Code Online (Sandbox Code Playgroud)

不幸的是,在这一点上,我并不完全确定如何处理这个问题.是否有可能编写一个函数将(mod)x 10添加到一个值,然后在x/10上再次调用相同的函数,直到x/10小于10?如果那不可能,我应该如何处理这个问题?

谢谢!

Yas*_*aev 11

sumd 0 = 0
sumd x = (x `mod` 10) + sumd (x `div` 10)
Run Code Online (Sandbox Code Playgroud)

然后运行它:

ghci> sumd 2345
14
Run Code Online (Sandbox Code Playgroud)

更新1:

这个不生成thunk并使用累加器:

sumd2 0 acc = acc
sumd2 x acc = sumd2 (x `div` 10) (acc + (x `mod` 10))
Run Code Online (Sandbox Code Playgroud)

测试:

ghci> sumd2 2345 0
14
Run Code Online (Sandbox Code Playgroud)

更新2:

部分应用版本采用无点样式:

sumd2w = (flip sumd2) 0
Run Code Online (Sandbox Code Playgroud)

测试:

ghci> sumd2w 2345
14
Run Code Online (Sandbox Code Playgroud)

flip在这里使用是因为函数由于某种原因(可能是由于GHC设计)不能用累加器作为第一个参数.


new*_*cct 11

为什么不呢

sumd = sum . map Char.digitToInt . show
Run Code Online (Sandbox Code Playgroud)

  • 我发现通过字符串和字符是非常不自然的,因为问题中没有任何与字符串有关的东西.这只是数字,解决方案应该反映出来. (6认同)

Mtn*_*ark 5

这只是@ ony的一个变种,但是我怎么写它:

import Data.List (unfoldr)

digits :: (Integral a) => a -> [a]
digits = unfoldr step . abs
    where step n = if n==0 then Nothing else let (q,r)=n`divMod`10 in Just (r,q)
Run Code Online (Sandbox Code Playgroud)

这将产生从低到高的数字,虽然读数不自然,但通常是涉及数字数字的数学问题.(项目欧拉有人吗?)另请注意,0生成[]和负数被接受,但产生绝对值的数字.(我不想要部分功能!)

另一方面,如果我需要一个数字的数字,因为它们是通常写的,那么我会使用@ newacct的方法,因为问题基本的正字法,而不是数学:

import Data.Char (digitToInt)

writtenDigits :: (Integral a) => a -> [a]
writtenDigits = map (fromIntegral.digitToInt) . show . abs
Run Code Online (Sandbox Code Playgroud)

比较输出:

> digits 123
[3,2,1]
> writtenDigits 123
[1,2,3]

> digits 12300
[0,0,3,2,1]
> writtenDigits 12300
[1,2,3,0,0]

> digits 0
[]
> writtenDigits 0
[0]
Run Code Online (Sandbox Code Playgroud)

在做Euler项目时,我实际上发现有些问题需要一个,有些则需要另一个问题.

关于.和"无点"风格

为了让那些不熟悉Haskell .运算符和"无点"风格的人明白这些,可以将它们重写为:

import Data.Char (digitToInt)
import Data.List (unfoldr)

digits :: (Integral a) => a -> [a]
digits i = unfoldr step (abs i)
    where step n = if n==0 then Nothing else let (q,r)=n`divMod`10 in Just (r,q)

writtenDigits :: (Integral a) => a -> [a]
writtenDigits i = map (fromIntegral.digitToInt) (show (abs i))
Run Code Online (Sandbox Code Playgroud)

这些与上面完全相同.您应该知道这些是相同的:

f . g
(\a -> f (g a))
Run Code Online (Sandbox Code Playgroud)

而"无点"意味着它们是相同的:

foo a = bar a
foo   = bar
Run Code Online (Sandbox Code Playgroud)

结合这些想法,这些是相同的:

foo a = bar (baz a)
foo a = (bar . baz) a
foo   = bar . baz 
Run Code Online (Sandbox Code Playgroud)

laster是惯用的Haskell,因为一旦你习惯了它,你可以看到它非常简洁.


jkr*_*mer 5

总结一个数字的所有数字:

digitSum = sum . map (read . return) . show
Run Code Online (Sandbox Code Playgroud)

show将数字转换为字符串.map迭代字符串的单个元素(即数字),将它们转换为字符串(例如字符'1'变为字符串"1")并读取它们将它们变回整数.总和最后计算总和.