我有一个函数,它接受一个子字符串和一个字符串,并在字符串中查找匹配的子字符串,并将匹配的字符更改为大写。例如:
> 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"
仅更改最后一个子字符串。这个函数出了什么问题,我可以编写一个函数来执行示例操作吗?
答案 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
,其中b
和a
实际上都是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}}(或其他)幺半群经常提供折叠的好方法。