是否有可能使这个递归函数无点?

时间:2016-12-04 17:05:38

标签: haskell

我有一个简单的功能,以及理解无点风格的愿望。

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)。我主要对使用函数的无点使用递归感兴趣。

如果可以(或者不是)可以无点地编写这个功能,我缺少什么?

3 个答案:

答案 0 :(得分:7)

正如@n.m所说,你可以使用shout = map toUpper。但是,可以在没有map或任何其他奇特函数(如foldr)的情况下执行此操作,但我们需要更多组合器。我们需要一些接受输入参数的东西并将其传递给两个函数toUpper . headshout . 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的惯例推动的。 maybeeither是与bool共享此精确模式的另外两个函数。

答案 1 :(得分:2)

要以无点样式重写任何内容,请安装pointfree或使用任何一个在线版本(http://pointfree.iohttps://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这样的组合也可能不是内部无点,但使用它们并不会像欺骗一样感觉。它们只处理函数,因此感觉比boolmap更具基础。

答案 2 :(得分:1)

进行递归的无点方法是使用Data.Function.fix,这在此解释:https://en.wikibooks.org/wiki/Haskell/Fix_and_recursion