我是一名C ++程序员,正在尝试自学Haskell,并且证明它正在挑战把握使用函数作为一种循环的基础知识。我有一个很大的数字,50!,我需要添加其数字的总和。这是一个相对简单的C ++循环,但我想学习如何在Haskell中完成它。
我已经阅读了一些介绍性指南,并且能够获得50分!与
sum50fac.hs ::
fac 0 = 1
fac n = n * fac (n-1)
x = fac 50
main = print x
不幸的是,在这一点上我并不完全确定如何处理这个问题。 是否有可能编写一个函数将(mod)x 10添加到一个值,然后在x / 10上再次调用相同的函数,直到x / 10小于10?如果那不可能,我应该如何解决这个问题呢?
谢谢!
答案 0 :(得分:11)
为什么不
sumd = sum . map Char.digitToInt . show
答案 1 :(得分:10)
sumd 0 = 0
sumd x = (x `mod` 10) + sumd (x `div` 10)
然后运行它:
ghci> sumd 2345
14
更新1:
这个不会生成thunk并使用accumulator:
sumd2 0 acc = acc
sumd2 x acc = sumd2 (x `div` 10) (acc + (x `mod` 10))
测试:
ghci> sumd2 2345 0
14
更新2:
pointfree样式的部分应用版本:
sumd2w = (flip sumd2) 0
测试:
ghci> sumd2w 2345
14
我在这里使用flip
因为某些原因(可能是由于GHC设计)的函数不能用累加器作为第一个参数。
答案 2 :(得分: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)
这将产生从低到高的数字,虽然不自然的读数,通常是你想要的涉及数字数字的数学问题。 (Project Euler任何人?)另请注意,0
生成[]
,并且接受负数,但会产生绝对值的数字。 (我不想要部分功能!)
另一方面,如果我需要一个数字的数字,因为它们通常被编写,那么我会使用@ newacct的方法,因为问题 基本上是正字法,而不是数学:
import Data.Char (digitToInt)
writtenDigits :: (Integral a) => a -> [a]
writtenDigits = map (fromIntegral.digitToInt) . show . abs
比较输出:
> 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]
在做Project 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))
这些与上面完全相同。您应该知道这些是相同的:
f . g
(\a -> f (g a))
“无点”意味着它们是相同的:
foo a = bar a
foo = bar
结合这些想法,这些是相同的:
foo a = bar (baz a)
foo a = (bar . baz) a
foo = bar . baz
laster是惯用的Haskell,因为一旦你习惯了它,你可以看到它非常简洁。
答案 3 :(得分:5)
总结一个数字的所有数字:
digitSum = sum . map (read . return) . show
show将数字转换为字符串。 map迭代字符串的单个元素(即数字),将它们变成一个字符串(例如字符'1'变成字符串“1”)并读取它们将它们变回整数。总和最后计算总和。
答案 4 :(得分:1)
只是为了让解决方案更加出色:
miterate :: (a -> Maybe (a, b)) -> a -> [b]
miterate f = go . f where
go Nothing = []
go (Just (x, y)) = y : (go (f x))
sumd = sum . miterate f where
f 0 = Nothing
f x = Just (x `divMod` 10)
答案 5 :(得分:0)
好吧,其中一个,你的Haskell函数错过了括号,你需要fac(n - 1)。 (哦,我看到你现在修好了)
二,真正的答案,你想要的是先列出一个清单:
listdigits n = if n < 10 then [n] else (listdigits (n `div` 10)) ++ (listdigits (n `mod` 10))
这应该只是组成所有数字的列表(类型:Int - &gt; [Int])。
然后我们只是总和(listdigits n)。我们应该完成。
当然,您可以将上面的示例概括为许多不同基数的列表,同样,您也可以轻松地将其转换为产品。
答案 6 :(得分:0)
虽然可能没有其他例子那么有效,但这是一种不同的接近方式:
import Data.Char
sumDigits :: Integer -> Int
sumDigits = foldr ((+) . digitToInt) 0 . show
编辑:newacct的方法非常相似,我更喜欢它: - )