Haskell中的点自由函数 - 将参数转换为列表

3

我正在学习以 point-free 方式使用 Haskell 中的一些函数。在尝试重写一些简单的例子时,我卡在了这个例子上:

func a b c d = sum $ take 2 $ sort [a, b, c, d]

如何将参数转换为列表形式,以便无需在左侧手动输入 a b c


11
但是,你为什么会想要那个东西呢?这段代码的功能是将一个列表中前两个最小的元素相加,然后将结果作为一个只包含该结果的新列表返回。 - n. m.
5
sum . take 2 . sort $ [a, b, c, d] 更易于理解。 - Will Ness
@n.m 正在学习TUM的课程材料,并发现人们需要最小化令牌才能赢得课堂比赛。因此,我考虑使用技巧来省略参数,并尝试使用点无关风格。 - user10661584
5
请注意,[a, b, c, d]只是: a ((:) b ((:) c ((:) d [])))的语法糖。点无风格表示法无法获得这种语法糖的好处,所以你已经开始得很不好了。 - Joseph Sible-Reinstate Monica
2个回答

2

评论中有人提到了很棒。

((((((sum . take 2) .) . sort) .) .) .) . (. ((. ((. return) . (:))) . (.) . (:))) . (.) . (.) . (:)

函数。

根据 http://pointfree.io

((((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

计算函数将通过部分应用的 `.` 应用于 `b`:
((((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来检查我的函数链是否可以以更简单的方式表达。关键是要找到黄金平衡点-在某些情况下,这种形式可以帮助,但有时它不仅是“无点”符号,而且还是“无意义”的符号。


2
如果我想在实际代码中以pointfree的方式编写这段代码,我只需将列表的构建分离出来:最初的回答。
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 (:)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接