Haskell - 结合折叠和复制?

时间:2015-08-07 15:19:52

标签: haskell fold

现在我一般都知道如何使用foldr,我通常会考虑使用递归函数,例如,当我看到时,对我来说:

   sum xs = foldr (+) 0 xs

我的想法是:

   sum [] = 0
   sum (x:xs) = x + sum xs

据我所知,这基本上就是foldr的意思。

现在,我有这段代码:

   printLine :: [Int] -> String
   printLine [] = "+"
   printLine (x:xs) = '+' : replicate x '-' ++ printLine xs

它的作用是,例如[5,4],然后打印“+ ----- + ---- +”。现在,我真的想知道如何使用foldr编写这个。它遵循递归函数的一般概念,所以我认为它应该是可行的。我尝试过使用lambda函数并翻转复制恶作剧,但似乎没有任何效果。有什么提示吗?

4 个答案:

答案 0 :(得分:3)

试试这个:

withFoldr :: [Int] -> String
withFoldr xs = foldr go "+" xs
  where go x b = ('+' : replicate x '-') ++ b

一般来说,当你有一个表达式

f as = foldr go a bs

然后a等于f []go函数具有签名go :: a -> b -> b 并且对应于printLine的递归情况:

-- match up with go :: a -> b -> b
printLine (x:xs) = '+' : replicate x '-' ++ printLine xs

在此,我们将axbprintLine xs联系起来,以便go成为:

go a b = ('+' : replicate a '-') ++ b

答案 1 :(得分:3)

另一种可能性:

$scope.categories

答案 2 :(得分:2)

你可以用很少的改变来编写它的一个版本:

printL = foldr alg "+" where
  alg x xs = '+' : replicate x '-' ++ xs

xs视为已经适当处理的组件可能会有所帮助;您处理x(通过将'+'添加到-复制x次),然后将“已处理”xs附加到该页面。

答案 3 :(得分:2)

我猜你想要一个无点表示作为学术练习传递给foldr。以下是我将如何处理这个问题。

首先,我会使用lambdas编写表达式:

Prelude> let pp = foldr (\x -> \s -> s ++ (replicate x '-') ++ "+") "+"
Prelude> pp [4,5]
"+-----+----+"

现在,我会努力让表达式一次点一个参数。首先,取消s

Prelude> let pp = foldr (\x -> flip (++) ((replicate x '-') ++ "+")) "+"
Prelude> pp [4,5]
"+-----+----+"

现在,x,首先将其移动为内部函数的最后一个参数:

Prelude> let pp = foldr (\x -> flip (++) ((flip replicate '-' x) ++ "+")) "+"
Prelude> pp [4,5]
"+-----+-

然后又迈出了一步:

Prelude> let pp = foldr (\x -> flip (++) (flip (++) "+" (flip replicate '-' x))) "+"
Prelude> pp [4,5]
"+-----+----+"

现在这有点失控,所以这是下一步的简写:

Prelude> let f = flip (++)
Prelude> let g = f "+"
Prelude> let h = flip replicate '-'
Prelude> let pp = foldr (\x -> f (g (h x))) "+"

让最后一点免费很容易!

Prelude> let pp = foldr (f . g . h) "+"
Prelude> pp [4,5]
"+-----+----+"

现在替换fgh,您就会得到答案。但是,这应该只是一个学术练习,我不会想象在实际的生产代码中使用这样的东西。

@WillNess建议使用我完全忘记的operator sections (see right section)。它们允许人们在两个地方省略翻转,导致更加令人讨厌的事情:

原件:

Prelude> let pp = foldr ((flip (++)) . (flip (++) "+") . (flip replicate '-')) "+"

更改为:

Prelude> let pp = foldr ((flip (++)) . (++ "+") . (`replicate` '-')) "+"
Prelude> pp [4,5]
"+-----+----+"