简体   繁体   English

是否有可能使该递归函数无指向性?

[英]Is it possible to make this recursive function point-free?

I have a simple function, and the desire to make sense of point-free style. 我有一个简单的功能,并且渴望表达无意义的风格。

shout :: String -> String
shout input
  | null input = []
  | otherwise = (toUpper . head $ input) : (shout . tail $ input)

My intuition led me to this 我的直觉使我想到了这一点

pfShout :: String -> String
pfShout = (toUpper . head) : (shout . tail)

which is complaining about the following for the first argument of the cons cell 这是抱怨cons单元的第一个参数以下

Couldn't match expected type 'String -> String' with actual type '[[Char] -> Char]' 无法将预期的类型'String-> String'与实际类型'[[Char]-> Char]'相匹配

  • Possible cause: '(:)' is applied to too many arguments 可能的原因:'(:)'应用于过多的参数

    In the expression: (toUpper . head) : (pfShout . tail) 在表达式中:(toUpper。head):(pfShout。tail)

    In an equation for 'pfShout': pfShout = (toUpper . head) : (pfShout . tail) 在'pfShout'的方程式中:pfShout =(toUpper。head):(pfShout。tail)

and complaining about this for the second argument of the cons cell 并在cons单元的第二个争论中对此抱怨

Couldn't match expected type '[[Char] -> Char]' with actual type '[Char] -> String' 无法将预期类型'[[Char]-> Char]'与实际类型'[Char]-> String'相匹配

  • Probable cause: '(.)' is applied to too few arguments 可能的原因:'(。)'应用于太少的参数

    In the second argument of '(:)', namely '(pfShout . tail)' 在'(:)'的第二个参数中,即'(pfShout。tail)'

    In the expression: (toUpper . head) : (pfShout . tail) 在表达式中:(toUpper。head):(pfShout。tail)

    In an equation for 'pfShout': pfShout = (toUpper . head) : (pfShout . tail) 在'pfShout'的方程式中:pfShout =(toUpper。head):(pfShout。tail)

It's clear to me that I can't make a list out of 'String -> String' functions and '[[Char]->Char]', and I'm starting to get a to a place where I'm thinking this just isn't gonna work point-free. 对我来说很明显,我无法从“字符串->字符串”函数 “ [[[Char]-> Char]””中列出一个列表,而我开始涉足这个领域只是不能毫无意义地工作。

I understand there are other considerations here (like now I'm missing a base-case), but . 我了解这里还有其他注意事项(例如现在我缺少一个基本案例),但是。 I also understand I could completely re-write the function to achieve the same effect (like map toUpper ). 我也了解我可以完全重写该函数以实现相同的效果(例如map toUpper )。 I'm primarily interested in point-free using recursion with the function as it is written. 我主要对将递归与函数结合使用时的无点使用感兴趣。

If it is (or isn't) possible to write this function point-free, what am I missing? 如果可以(或不可能)无点编写此函数,我会缺少什么?

As @nm noted you can use shout = map toUpper . 正如@nm所指出的,您可以使用shout = map toUpper However it is possible to do this without map or any other fancy functions like foldr , but we need more combinators. 但是,可以在没有map或其他任何喜欢的功能(例如foldr )的情况下执行此操作,但是我们需要更多的组合器。 We need something that takes our input argument and passes it to two functions toUpper . head 我们需要toUpper . head输入参数的东西,并将其传递给两个函数toUpper . head toUpper . head and shout . tail toUpper . head shout . tail shout . tail and then combines them with : . shout . tail然后将它们与: You propably don't know this function yet, but the <*> operator from applicative has what we need: 您可能还不知道此功能,但是applicative的<*>运算符具有我们所需的功能:

(f <*> g) x = f x (g x)

Now we can do something like this: 现在我们可以做这样的事情:

combine . f <*> g = \x -> combine (f x) (g x) -- [1]

I will let you figure out how exactly to apply this to your problem. 我将让您弄清楚如何将其正确应用于您的问题。 ;) ;)

But we still need to express the empty list case somehow. 但是,我们仍然需要以某种方式表达空白清单的情况。 There are multiple ways to do this but the easiest would be the bool from Data.Bool function which is like an if function, together with join from Control.Monad . 有多种方法可以执行此操作,但最简单的方法是Data.Bool函数中的bool (类似于if函数)以及Control.Monad join

-- [2]
bool x _ False = x
bool _ x True  = x

join f x = f x x

Now we can do the following: 现在,我们可以执行以下操作:

shout = join $ bool (not null case) (null case) . null
-- Which translates to
shout xs = bool ((not null case) xs) ((null case) xs) (null xs)

Again implementing the two cases is left as an excercise to the reader. 再次执行这两种情况留给读者练习。

[1]: Instead of (.) you could also use (<$>) which for functions is the same as (.) but (<$>) and (<*>) kind of belong together. [1]:除了(.)您还可以使用(<$>) ,它的功能与(.)相同,但是(<$>)(<*>)属于同一类。 You will understand why once you learn about applicatives. 您将了解为什么一旦学习了应用程序。

[2]: If you wonder what the reasoning behind the order of the arguments of bool is, the first argument is the False case because Bool is defined like this: [2]:如果您想知道bool参数的顺序背后的原因是什么,第一个参数是False情况,因为Bool的定义如下:

data Bool = False | True

And this order is motivated by the convention that False < True . 并且此顺序是由False < True的约定驱动的。 maybe and either are two other functions that share this exact pattern with bool . maybe并且eitherbool共享这个确切模式的另外两个函数。

To rewrite anything in a pointfree style, install pointfree or use any one of the online versions ( http://pointfree.io or https://blunt.herokuapp.com ). 要以无点样式重写任何内容,请安装点样式或使用任何一种在线版本( http://pointfree.iohttps://blunt.herokuapp.com )。

Your expression 你的表情

\input -> (toUpper . head $ input) : (shout . tail $ input)

translates to 转换为

ap ((:) . toUpper . head) (shout . tail)

(You can substitute <*> for ap , they are interchangeable in this case). (您可以用<*>代替ap ,在这种情况下,它们可以互换)。

But this is not enough. 但这还不够。 You also need to somehow end the recursion. 您还需要以某种方式结束递归。 To do that in the pointfree style you need a pointfree if or a pointfree pattern match which do not seem to exist in Haskell. 要以无点样式进行操作,您需要无点if或无点模式匹配,这在Haskell中似乎不存在。 In theory if could be defined as a built-in function, which would make a pointfree definition possible, but in Haskell it isn't. 从理论上讲, if可以将其定义为内置函数,这将使无点定义成为可能,但在Haskell中则不是。 (One can define such a function, but its implementation would not be pointfree. So you can trade map for Data.Bool.bool , but is there a point? (可以定义一个这样的函数,但是它的实现不是没有意义的。因此,您可以将map Data.Bool.bool ,但是有一点吗?

Combinators like . 组合喜欢. and $ and even ap are probably not internally pointfree either, but using them doesn't feel like cheating. $甚至ap可能在内部也不是没有意义的,但是使用它们不会让人作弊。 They only deal with functions, and thus feel somehow more fundamental than bool or map . 它们只处理函数,因此感觉比boolmap更根本。

进行递归的无点方法是使用Data.Function.fix ,在这里对此进行了说明: https : Data.Function.fix

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM