【问题标题】:Tacit programming style using F#使用 F# 的隐性编程风格
【发布时间】:2011-02-17 02:41:02
【问题描述】:

这不是一个实际重要的问题,但我希望在 F# 中看到 tacit programming 的示例,其中我的 point-free 函数可以有多个参数(不是列表形式或元组)。

其次,这些函数如何操作复杂的数据结构。我正在 F# Interactive 中尝试,但还没有成功。

我试过了,例如:

> (fun _ -> (fun _ -> (+))) 333 222 111 555

这样对吗?

还有:

> (fun _ -> (fun _ -> (+))) "a" "b" "c" "d";;  

val it : string = "cd"

【问题讨论】:

  • 你应该使用“point-free”而不是“pointless”。这是标准术语。 :)

标签: f# tacit-programming


【解决方案1】:

在 F# 中,函数的数量是固定的,因此您无法同时编写两者

(op) 1 2

(op) 1 2 3 4

对于任何给定的运算符op。如果这是您想要的,您将需要使用列表或其他数据结构。如果你只是想避免命名变量,你总是可以做“1 + 2 + 3 + 4”。在 F# 中添加数字列表最惯用的方法是 List.sum [1;2;3;4],这也避免了变量。

【讨论】:

    【解决方案2】:

    F# 不包含 Haskell 中可用的一些基本函数(主要是因为 F# 程序员通常更喜欢显式的编程风格,并且仅在不损害可读性的最明显的情况下使用无点风格)。

    但是,您可以像这样定义一些基本组合器:

    // turns curried function into non-curried function and back
    let curry f (a, b) = f a b
    let uncurry f a b = f (a, b)
    
    // applies the function to the first/second element of a tuple
    let first f (a, b) = (f a, b)
    let second f (a, b) = (a, f b)
    

    现在您可以使用组合器实现添加两个字符串长度的功能,如下所示:

    let addLengths = 
      uncurry (( (first String.length) >> (second String.length) ) >> (curry (+)))
    

    这构造了两个函数,将String.length 应用于元组的第一个/第二个元素,然后组合它们,然后使用+ 添加元组的元素。整个东西都包裹在uncurry 中,所以你得到了一个string -> string -> int 类型的函数。

    【讨论】:

    • 我已经在 FSI 中检查过了,它确实有效!非常感谢;顺便说一句,你能解释一下你是如何得到元组函数组合语法的吗?我的意思是(first String.length) >> (second String.length) 这对我来说有点不寻常;)
    • 这是使用函数组合>> 实现的。例如f >> g 表示对于参数x,它将调用g(f(x))。在上述情况下,第一个函数 (first String.length) 将元组 string * string 转换为元组 int * string,第二个函数 (second String.length) 将其转换为包含长度的 int * int
    • 您实际上是在为 F# 实现箭头;)好吧,为什么不呢 - 箭头是作为 monad 和默认编程的组合而发明的。
    猜你喜欢
    • 2011-11-19
    • 2010-11-08
    • 2011-08-24
    • 1970-01-01
    • 2016-01-05
    • 2017-08-20
    • 1970-01-01
    • 2011-06-02
    • 1970-01-01
    相关资源
    最近更新 更多