我刚开始学习Haskell。我想知道是否有人可以帮助我进行for-style循环。在Perl中,这就是我能做的:
#!/usr/bin/perl
my $total = 0;
for (my $n=0, my $i=1; $i<=10; $i++, $n+=50) {
$total += $n;
print "iteration:$i\t", "n:$n\t", "total:$total", "\n";
}
如何在Haskell中获得相同的输出?谢谢。
答案 0 :(得分:2)
所以看起来你的代码打印出部分总和。所以,让我们这样做!
您从$n
开始迭代0
,然后递增50
十次。而不是将其作为循环,更多的Haskelly方法是创建一个包含n
的所有值的列表。
-- take the first 10 elements from the sequence that starts 0, 50, 100, 150...
let ns = take 10 [0, 50..]
现在我们真的想要这个序列的部分和,所以让我们计算一下。我们可以编写自己的函数来执行此操作,但这正是Prelude.scanl1
的用途:
-- calculates the sequence 0, 0 + 50, 0 + 50 + 100, 0 + 50 + 100 + 150, ...
let totals = scanl1 (+) ns
现在我们有了总计,唯一真正的工作就是打印它们以及相应的i
和n
。所以我们需要i
值列表:
let is = [1..10]
现在我们要同时遍历所有三个(n
,i
和total
),所以让我们创建一个新列表:
let triples = zip3 ns is totals
现在我们在代码中需要做的就是迭代这些三元组并打印我们的中间结果。在Haskell中,打印定义了IO操作,并且各个IO操作需要在它们运行之前进行组合,这是Control.Monad.forM_
所做的,将列表的每个元素上运行给定函数的结果组合成一个巨大的动作
forM_ triples $ \(n,i,total) ->
-- use show to convert Ints to Strings, and ++ to concatenate Strings
putStrLn $ "iteration:" ++ show i ++ "\tn:" ++ show n ++ "\ttotal:" ++ show total
或者一起:
module Main where
import Control.Monad (forM_)
main = do
-- take the first 10 elements from the sequence that starts 0, 50, 100, 150...
let ns = take 10 [0, 50..]
-- calculates the sequence 0, 0 + 50, 0 + 50 + 100, 0 + 50 + 100 + 150, ...
let totals = scanl1 (+) ns
let is = [1..10]
let triples = zip3 ns is totals
forM_ triples $ \(n,i,total) ->
-- use show to convert Ints to Strings, and ++ to concatenate Strings
putStrLn $ "iteration:" ++ show i ++ "\tn:" ++ show n ++ "\ttotal:" ++ show total
它有效!
% ghc SO26540775.hs && ./SO26540775
iteration:1 n:0 total:0
iteration:2 n:50 total:50
iteration:3 n:100 total:150
iteration:4 n:150 total:300
iteration:5 n:200 total:500
iteration:6 n:250 total:750
iteration:7 n:300 total:1050
iteration:8 n:350 total:1400
iteration:9 n:400 total:1800
iteration:10 n:450 total:2250
答案 1 :(得分:2)
将我的代码放在键盘的位置,这是我对@ rampion的答案的修改,使其在重复计数方面更加干燥。
module Main where
import Control.Monad (forM_)
main = do
-- take the sequence that starts 0, 50, 100, 150...
let ns = [0, 50..]
-- and calculate its partial sums:0, 0+50, 0+50+100, 0+50+100+150, ...
let totals = scanl1 (+) ns
-- throw in a list of indexes for counting: 1, 2, 3...
let is = [1..]
-- and zip them all together: (1,0,0),(2,50,50),(3,100,150), etc.
let triples = zip3 is ns totals
{- Note that so far, all of these sequences are infinitely long. Haskell
won't try to calculate any members of them until asked, but it will keep
calculating as long as you keep asking. Most languages won't even let you
define an infinite list, but that's where Haskell's laziness comes in
handy; the fact that these lists are unbounded does not cause any extra
work to be performed by the program.
Still, we only care about the first 10 elements of this list, so let's
grab those using take (which returns the first n elements of a list for
some number n) and then iterate over those and print them out: -}
forM_ (take 10 triples) $ \(i,n,total) ->
-- use show to convert Ints to Strings, and ++ to concatenate Strings
putStrLn $ "iteration:" ++ show i ++ "\tn:" ++ show n ++ "\ttotal:" ++ show total