我正在学习以 point-free 方式使用 Haskell 中的一些函数。在尝试重写一些简单的例子时,我卡在了这个例子上:
func a b c d = sum $ take 2 $ sort [a, b, c, d]
如何将参数转换为列表形式,以便无需在左侧手动输入 a b c
?
我正在学习以 point-free 方式使用 Haskell 中的一些函数。在尝试重写一些简单的例子时,我卡在了这个例子上:
func a b c d = sum $ take 2 $ sort [a, b, c, d]
如何将参数转换为列表形式,以便无需在左侧手动输入 a b c
?
评论中有人提到了很棒。
((((((sum . take 2) .) . sort) .) .) .) . (. ((. ((. return) . (:))) . (.) . (:))) . (.) . (.) . (:)
函数。
((((sum . take 2 . sort) .) .) .) . (. ((. ((. return) . (:))) . (.) . (:))) . (.) . (.) . (:)
这也是正确的。
你不相信我吗?
好的
让我们对第二个选项进行β-还原(在我看来它看起来更好)。
(((((sum . take 2 . sort) .) .) .) . (. ((. ((. return) . (:))) . (.) . (:))) . (.) . (.) . (:) ) a b c d
a
:((((((sum . take 2 . sort) .) .) .) ((. ((. ((. return) . (:))) . (.) . (:))) ((.) ((.) ((:) a))))) ) b c d
增强运算符:
((((((sum . take 2 . sort) .) .) .) ((. ((. ((. return) . (:))) . (.) . (:))) (((a:).).))) ) b c d
应用部分应用组合:
((((sum . take 2 . sort) .) .) . ((. ((. ((. return) . (:))) . (.) . (:))) (((a:).).))) b c d
b
:((((sum . take 2 . sort) .) .) (((. ((. ((. return) . (:))) . (.) . (:))) (((a:).).)) b)) c d
((((sum . take 2 . sort) .) .) ( (((a:).).) . ((. ((. return) . (:))) . (.) . (:)) $ b)) c d)
解决组合:
((((sum . take 2 . sort) .) .) ( (((a:).).) (((. ((. return) . (:))) . (.) . (:)) b))) c d
申请到 b
:
((((sum . take 2 . sort) .) .) ( (((a:).).) ((. ((. return) . (:))) ((b:) .)))) c d
应用组合(2x):
(((sum . take 2 . sort) .) . ((((a:).).) (( ((b:) .) . ((. return) . (:)))))) c d
应用于 c
并解决组合问题:
((sum . take 2 . sort) .) (((((a:).).) (( ((b:) .) . ((. return) . (:))))) c) d
应用部分应用组合:
((sum . take 2 . sort) .) (((((a:).) . (( ((b:) .) . ((. return) . (:)))))) c) d
应用于c
并解决组合:
((sum . take 2 . sort) .) (((a:).) ((( ((b:) .) . ((. return) . (:)))) c)) d
应用于 c
并解决组合:
((sum . take 2 . sort) .) (((a:).) (((b:) .) (((. return) . (:)) c))) d
解决组合:
((sum . take 2 . sort) .) ((a:) . (((b:) .) (((. return) . (:)) c))) d
应用部分应用组合:
((sum . take 2 . sort) . ((a:) . (((b:) .) (((. return) . (:)) c)))) d
解决组合:
(sum . take 2 . sort) (((a:) . (((b:) .) (((. return) . (:)) c))) d)
应用于 d
并解决组合:
(sum . take 2 . sort) ((a:) ((((b:) .) (((. return) . (:)) c)) d))
应用部分应用组合:
(sum . take 2 . sort) ((a:) (((b:) . (((. return) . (:)) c)) d))
应用于 d
并解决组合:
(sum . take 2 . sort) ((a:) (((b:) ((((. return) . (:)) c) d))))
应用于c
并解决组合:
(sum . take 2 . sort) ((a:) (((b:) (((((c:). return))) d))))
应用于 d
并解决组合:
(sum . take 2 . sort) ((a:) ((b:) ((c:) (return d))))
将中缀运算符转换并解析return
(sum . take 2 . sort) (a : (b : (c : (d : []))))
糖化
(sum . take 2 . sort) [a, b, c, d]
解决组合并使用$
运算符
sum $ take 2 $ sort $ [a, b, c, d]
我们回来了!如果你把它粘贴到带有彩虹括号的编辑器中,阅读将更容易。
正如您所见,并非所有内容都以pointfree形式更加优雅。有时它非常复杂,可能很难理解函数为什么起作用,甚至不知道它到底做了什么。请注意,此函数是长度特定的-如果您尝试以这种方式创建更大的列表,它将变得更大。
另一方面,我经常使用http://pointfree.io来检查我的函数链是否可以以更简单的方式表达。关键是要找到黄金平衡点-在某些情况下,这种形式可以帮助,但有时它不仅是“无点”符号,而且还是“无意义”的符号。
list4 a b c d = [a, b, c, d]
under3 = fmap . fmap . fmap
func = under3 (sum . take 2 . sort) . list4
func 30 4 1000 200 == 34
< p > under3
使用 fmap
在 (->) a
函子中“跳过” 3 个参数,这样我们就可以将一个一元函数 (sum . take2 . sort
) 与一个四元函数 (list4
) 组合起来。这种使用 fmap
的方式与组合 (.)
完全等价,只是比内联更易读,因为它在记忆上是“映射”参数:
func = ((((sum . take 2 . sort) .) .) .) . list4
where
…
list4
本身并不需要变成pointfree的形式,因为没有比pointful版本更易读和简洁的直接方法。如果你愿意在反向构建列表后再reverse
它,那么你可以以稍微更易读的pointfree方式编写它,但它仍然有点长而且不太清晰:
list4 = under3 reverse . fmap (fmap cons . cons) . cons . pure
where cons = flip (:)
sum . take 2 . sort $ [a, b, c, d]
更易于理解。 - Will Ness[a, b, c, d]
只是: a ((:) b ((:) c ((:) d [])))
的语法糖。点无风格表示法无法获得这种语法糖的好处,所以你已经开始得很不好了。 - Joseph Sible-Reinstate Monica