用于将修改顺序应用于字符串的函数

时间:2014-01-01 18:58:22

标签: haskell

我有一个函数,它接受一个子字符串和一个字符串,并在字符串中查找匹配的子字符串,并将匹配的字符更改为大写。例如:

> upperCase "aaa" "---aaa---"
"---AAA---"

我想使用这个函数,但是使用几个子串应用upperCase操作。例如:

> upperCases ["aaa", "bbb", "c"] "d---aaa---c--bbb"
"d---AAA---C--BBB"

我正在努力理解的是我如何做到这一点。这是我最好的尝试:

upperCases [] st = st
upperCases [x] st = upperCase x st
upperCases (x:xs) st = upperCases xs st

当我在上面的示例中使用此upperCases函数时,我得到以下错误输出:

"d---aaa---C--bbb"

仅更改最后一个子字符串。这个函数出了什么问题,我可以编写一个函数来执行示例操作吗?

2 个答案:

答案 0 :(得分:6)

你只是从模式x“扔掉”x:xs。显然,在递归到其他匹配之前,您需要先使用它!

upperCases (x:xs) st = upperCases xs $ upperCase x st

但是,最好不要明确地写出递归。你想要的基本上是将一堆功能链接在一起。这是一个折叠:

chain :: [a -> a] -> a -> a
chain = foldr (.) id

现在,目前你没有函数a->a。相反,您有b->a->a,其中ba实际上都是String。但是你可以部分地应用第一个参数,例如

[upperCase "aaa", upperCase "bbb", upperCase "c"] :: [String -> String]

更简洁地说,此列表可以由map upperCase ["aaa", "bbb", "c"]定义。

总而言之,你需要

upperCases = foldr (.) id . map upperCase

实际上,您甚至可以将upperCase包含在折叠中:

upperCases = foldr ((.) . upperCase) id

答案 1 :(得分:4)

我想在leftaroundabout的答案中添加一个小注释:从结构映射到自身的函数在数学中称为endomorphism。在Haskell中,可以直接将a类型上的所有函数(endomorphisms)集合表示为a -> a,并且我们有一个名为Endo的数据类型。

由于使用.可以合成内同态,因为任何f我们f . id等于id . f等于f,它们自然形成Monoid 3}}。这个幺半群有时被称为monoid。在Haskell中,Endo upperCases实例见证了这一点。

现在这些函数的组合只是组合这个幺半群中的元素。因此,我们可以将import Data.Monoid upperCases :: [String] -> String -> String upperCases = appEndo . mconcat . map (Endo . upperCase) 定义为

Endo

我们首先将字符串模式映射到它们各自的内同态中,将它们连接在它们的monoid中,然后只提取结果函数。

使用{{1}}(或其他)幺半群经常提供折叠的好方法。