可以用无点样式编写此函数吗?如果没有,为什么? [英] Can this function be written in point-free style? If not, why?
问题描述
一个相关的问题是此,但是有些答案说几乎所有东西都可以成为无积分的,那么这个功能有什么问题呢?
\[x] -> x
http://pointfree.io/似乎无法以无点样式编写.这是否意味着它不能以这种方式编写?如果是这样,其理论原因是什么?
我只能观察到上面的函数是一个残缺的"函数.head
(或last
,fwiw)的版本,只能在单例列表上运行.实际上,应用于非单例列表时,它会在ghci
中以这种方式出错: *** Exception: <interactive>:380:5-13: Non-exhaustive patterns in lambda
也许非穷举"是指模式上的原因是为什么某些函数不能以无点样式编写?
根据答案进行
我没想到我的问题的答案会如此复杂(我觉得我只是以为简短的答案实际上是不,它不能),所以我需要花点时间仔细阅读它们,进行一些试验,然后将我的想法环绕在它们周围,否则我无法决定应该接受哪个.暂时将乔恩·普迪(Jon Purdy)的答案+1,直到这是我在普通代码中会停止的地方.
当然,几乎所有 都可以做成无指向性的.棘手的事情是在结果表达式中将允许使用哪些函数.如果我们进行模式匹配,则通常需要使用fold函数来进行匹配.因此,例如,如果我们在Maybe a
上进行模式匹配,则需要将其替换为 extra
.当然,对于这个小例子,我们可以很容易地自己编写.
list :: b -> (a -> [a] -> b) -> ([a] -> b)
list f g x = case x of
[] -> f
(y:ys) -> g y ys
现在,我们可以轻松地将其应用于您的\[x] -> x
.首先,让我们写出函数的实际功能,包括所有混乱的undefined
情况(为简便起见,我将使用undefined
而不是一长串错误消息)
func :: [a] -> a
func x = case x of
[] -> undefined
(y:ys) -> case ys of
[] -> y
(_:_) -> undefined
现在,每个case语句都与每个构造函数完全匹配一次.可以折叠成纸了.
func :: [a] -> a
func x = case x of
[] -> undefined
(y:ys) -> list y undefined ys
现在我们也可以转换外壳
func :: [a] -> a
func x = list undefined (\y -> list y undefined) x
所以我们有
func :: [a] -> a
func = list undefined (\y -> list y undefined)
或者,如果我们想对此真正发疯
func :: [a] -> a
func = list undefined (flip list undefined)
但是此功能不在基础中
是的,是的.我们通过使用不存在的折痕来作弊.如果要系统地执行此操作,则需要该fold运算符.但是,如果没有它,我们仍然可以将它与foldr1
一起使用,这足以满足我们的特定目的.
func' :: [a] -> a
func' = foldr1 (const (const undefined))
因此,为了回答您的问题,我们不能总是像您的示例中那样用pointfree系统地替换模式匹配, 除非我们具有具有正确签名的折叠功能.幸运的是,对于任何Haskell 98数据类型(可能还有GADT,但是我从任何深度都没有考虑过这种情况),可以始终编写该函数.但是即使没有这种支持,我们仍然可以使它正常工作.
One related question is this, but some of the answer say that almost anything can be made point free, so what is wrong with this function?
\[x] -> x
http://pointfree.io/ doesn't seem to be able to write it in point-free style. Does this mean that it cannot be written that way? If so, what is the theoretical reason for it?
I can only observe that the function above is a "crippled" version of head
(or last
, fwiw) which can only operate on singleton lists. Indeed, applied on non singleton lists, it errors this way in ghci
:
*** Exception: <interactive>:380:5-13: Non-exhaustive patterns in lambda
Maybe the "non-exhaustivity" on the pattern is the reason why some functions cannot be written in point-free style?
Edit in the light of the answers:
I did not expect that the answers to my question could be so complex (I feel I just thought that the short answer was no, it cannot, actually), so I need to find some time to read them carefully, experiment a bit, and wrap my mind around them, otherwise I cannot decide which one should be accepted. For the time being, +1 to Jon Purdy's answer, which I could easily understand up to This is where I would stop in ordinary code.
Sure, pretty much anything can be made pointfree. The tricky thing is what functions you'll allow in the resulting expression. If we pattern match, we generally need a fold function to do the matching instead. So, for instance, if we pattern matched on a Maybe a
, we'd need to replace that with maybe
. Similarly, Either a b
patterns can be written in terms of either
.
Note the pattern in the signatures
data Maybe a = Nothing | Just a
maybe :: b -> (a -> b) -> (Maybe a -> b)
Maybe a
has two constructors, one which takes no arguments and the other which takes an a
. So maybe
takes two arguments: one which is a 0-ary function (b
), and one which takes an a
(a -> b
), and then returns a function from Maybe a -> b
. The same pattern is present in either
data Either a b = Left a | Right b
either :: (a -> c) -> (b -> c) -> (Either a b -> c)
Two cases. The first takes an a
and produces whatever c
we want. The second takes a b
and produces whatever c
we want. In every case, we want one function for each possible term in the sum type.
In order to systematically pointfree a function like \[x] -> x
, we'd need a similar fold. [a]
is declared as, essentially
data [a] = [] | a : [a]
So we'd need a function with this signature
list :: b -> (a -> [a] -> b) -> ([a] -> b)
Now, flip foldr
comes close
flip foldr :: b -> (a -> b -> b) -> ([a] -> b)
But it's recursive. It calls its provided function on the [a]
part of a : [a]
. We want a true fold, which isn't provided by Haskell's base libraries. A quick Hoogle search tells us that this function does exist in a package though, called extra
. Of course, for this small example we can just write it ourselves very easily.
list :: b -> (a -> [a] -> b) -> ([a] -> b)
list f g x = case x of
[] -> f
(y:ys) -> g y ys
Now we can apply it to your \[x] -> x
easily. First, let's write what your function really does, including all of the messy undefined
cases (I'll use undefined
rather than a long error message here, for brevity)
func :: [a] -> a
func x = case x of
[] -> undefined
(y:ys) -> case ys of
[] -> y
(_:_) -> undefined
Now every case statement exactly matches each constructor once. This is ripe for transformation into a fold.
func :: [a] -> a
func x = case x of
[] -> undefined
(y:ys) -> list y undefined ys
And now we transform the outer case as well
func :: [a] -> a
func x = list undefined (\y -> list y undefined) x
So we have
func :: [a] -> a
func = list undefined (\y -> list y undefined)
Or, if we want to be truly crazy about it
func :: [a] -> a
func = list undefined (flip list undefined)
But this function isn't in base
Yeah, that's true. We kind of cheated by using a fold that didn't exist. If we want to do it systematically, we need that fold operator. But without it, we can still kludge it together with foldr1
, which suffices for our particular purposes.
func' :: [a] -> a
func' = foldr1 (const (const undefined))
So, to answer your question, we can't always systematically replace pattern matching like in your example with pointfree, unless we have a fold function with the right signature. Fortunately, that function can always be written, for any Haskell 98 data type (possibly GADTs as well, but I haven't considered that possibility in any depth). But even without that support, we can still make it work, kind of.
这篇关于可以用无点样式编写此函数吗?如果没有,为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!