我有一个简单的功能,以及理解无点风格的愿望。
shout :: String -> String
shout input
| null input = []
| otherwise = (toUpper . head $ input) : (shout . tail $ input)
我的直觉把我带到了这个
pfShout :: String -> String
pfShout = (toUpper . head) : (shout . tail)
正在抱怨cons小区的第一个参数
以下内容无法匹配预期类型'字符串 - >字符串' 实际类型' [[Char] - >字符]'
可能的原因:'(:)'适用于太多的参数
在表达式中:( toUpper.head):( pfShout.tr尾)
在' pfShout'的等式中: pfShout =(toUpper.head):( pfShout.tail)
并且抱怨这个因为第三个缺点的原因
无法匹配预期类型' [[Char] - >字符]' 实际类型' [Char] - >字符串'
可能的原因:'(。)'适用于太少的参数
在'(:)'的第二个论点中,即'(pfShout.tr尾)'
在表达式中:( toUpper.head):( pfShout.tr尾)
在' pfShout'的等式中: pfShout =(toUpper.head):( pfShout.tail)
我很清楚,我无法列出' String - >列表。字符串'函数和' [[Char] - > Char]',我开始到一个我认为这不是&的地方#39;要点工作。
我知道这里还有其他注意事项(比如现在我错过了一个基本情况),但是。我也明白我可以完全重写函数来达到同样的效果(比如map toUpper
)。我主要对使用函数的无点使用递归感兴趣。
如果可以(或者不是)可以无点地编写这个功能,我缺少什么?
答案 0 :(得分:7)
正如@n.m所说,你可以使用shout = map toUpper
。但是,可以在没有map
或任何其他奇特函数(如foldr
)的情况下执行此操作,但我们需要更多组合器。我们需要一些接受输入参数的东西并将其传递给两个函数toUpper . head
和shout . tail
,然后将它们与:
组合。你可能还不知道这个功能,但来自applicative的<*>
运算符有我们需要的东西:
(f <*> g) x = f x (g x)
现在我们可以这样做:
combine . f <*> g = \x -> combine (f x) (g x) -- [1]
我会告诉你如何将这个应用到你的问题中。 ;)
但我们仍然需要以某种方式表达空列表案例。有多种方法可以做到这一点,但最简单的方法是来自bool
函数的Data.Bool
,就像if
函数一样,以及来自join
的{{1}}。
Control.Monad
现在我们可以执行以下操作:
-- [2]
bool x _ False = x
bool _ x True = x
join f x = f x x
再次实施这两个案例仍然是读者的练习。
[1]:您还可以使用shout = join $ bool (not null case) (null case) . null
-- Which translates to
shout xs = bool ((not null case) xs) ((null case) xs) (null xs)
代替(.)
,(<$>)
功能与(.)
相同,但(<$>)
和(<*>)
属于一起。一旦你了解了应用程序,你就会明白为什么。
[2]:如果你想知道bool
的参数顺序背后的原因是什么,第一个参数是False
的情况,因为Bool
的定义如下: / p>
data Bool = False | True
这个顺序是由False < True
的惯例推动的。 maybe
和either
是与bool
共享此精确模式的另外两个函数。
答案 1 :(得分:2)
要以无点样式重写任何内容,请安装pointfree或使用任何一个在线版本(http://pointfree.io或https://blunt.herokuapp.com)。
你的表达
\input -> (toUpper . head $ input) : (shout . tail $ input)
转换为
ap ((:) . toUpper . head) (shout . tail)
(您可以将<*>
替换为ap
,在这种情况下它们可以互换。)
但这还不够。你还需要以某种方式结束递归。要以无点样式执行此操作,您需要一个在Haskell中似乎不存在的无点if
或无点模式匹配。理论上if
可以定义为内置函数,它可以使无点定义成为可能,但在Haskell中它不是。 (可以定义这样一个函数,但它的实现不是无点的。所以你可以用map
交换Data.Bool.bool
,但是有一点吗?
像.
和$
甚至ap
这样的组合也可能不是内部无点,但使用它们并不会像欺骗一样感觉。它们只处理函数,因此感觉比bool
或map
更具基础。
答案 2 :(得分:1)
进行递归的无点方法是使用Data.Function.fix
,这在此解释:https://en.wikibooks.org/wiki/Haskell/Fix_and_recursion