F#:管道与作曲与......作曲?

2024-03-25

我对一切都很陌生 - F#、一般编程以及这个社区。我是一名数学家,在本科期间曾短暂接触过计算机科学。我正在尝试用 F# 完成一些任务“F# 备忘单” http://dungpa.github.io/fsharp-cheatsheet/展示了三种不同的函数组合方式,但没有解释重复性。这是链接中的相关信息,看看我的意思。

The let 关键字还定义命名函数。

let negate x = x * -1 
let square x = x * x 
let print x = printfn "The number is: %d" x

let squareNegateThenPrint x = 
print (negate (square x)) 

管道操作员 |> 用于将函数和参数链接在一起。双反引号标识符可以方便地提高可读性,特别是在单元测试中:

let ``square, negate, then print`` x = 
    x |> square |> negate |> print

组合运算符 >> 用于组合函数:

let squareNegateThenPrint' = 
    square >> negate >> print

通过检查并在 VS F# 中与以下函数交互:

  1. squareNegateThenPrint x
  2. ``平方,求反,然后打印'' x
  3. squareNegateThenPrint'

看来这是实现完全相同的 3 种方法的列表 事物, 这里有什么细微差别吗?我确信给定相同的 int 它们都会返回相同的 int,但是除此之外呢?我是什么 我没看见吗?各自的优点和缺点是什么 三种方法?

2 和 3 都使用“运算符”,而 1 似乎是组合函数以从旧函数创建新函数的常用“数学”方式。我怀疑选项 3 确实等同于选项 1(从某种意义上说>>运算符被定义为square >> negate >> print实际上计算为print (negate (square x))但代码的可读性有所提高,因为您可以按照函数名称发生的顺序查看函数名称,而不是使用通常的数学符号的相反顺序,并且通过这种方式定义可以节省一两次击键,因为您不必包含x位于函数名称的末尾,因为>>运算符可能使左侧函数自动继承对右侧函数变量的依赖,而无需显式引用该变量。

那么管道方法是如何发挥作用的呢?是否是管道 运算符 一个更通用的运算符,恰好适用于 函数组成?

另外,我在谷歌上搜索了很多,并尝试在发布之前阅读文档,但我没有得到任何结果。我确信如果我继续学习这门语言,明年的某个时候我就会理解其中的差异。但我也相信这里有人可以加快这一过程并解释或提供一些很好的例子。最后,我并不精通 C#,也不精通任何其他语言(数学除外),因此对一个完全菜鸟而不仅仅是一个 f# 菜鸟的解释表示赞赏。谢谢!


首先- 是的,所有这些方式在“逻辑上”和编译到硬件时都是等效的。这是因为|> and >>运算符定义为inline。定义大致如下:

let inline (|>) x f = f x
let inline (>>) f g = fun x -> g (f x)

的含义inline关键字是编译器将以函数体替换对函数的调用,然后编译结果。因此,以下两者:

x |> f |> g
(f >> g) x

将被编译exactly与以下方式相同:

g (f x)

然而,在实践中,也存在一些问题。


其中一个问题是类型推断及其与类/接口的相互作用。考虑以下:

let b = "abcd" |> (fun x -> x.Length)
let a = (fun x -> x.Length) "abcd"

尽管这些定义在逻辑上和编译形式上都是等效的,但第一个定义将编译,而第二个定义则不会。发生这种情况是因为 F# 中的类型推断是从左到右进行的,没有双回,因此,在第一个定义中,当编译器到达x.Length,它已经知道x is a string,因此它可以正确解析成员查找。在第二个例子中,编译器不知道什么x是,因为它还没有遇到参数"abcd" yet.


另一个问题与恐惧有关值限制 http://mlton.org/ValueRestriction。简单来说,它的定义是句法上(不符合逻辑!)value(与函数相反)不能是通用的。这有与可变性有关的模糊原因 - 请参阅链接的文章以获取解释。

将其应用于函数组合,请考虑以下代码(请注意,两者f and g是通用函数):

let f x = [x]
let g y = [y]

let h1 = f >> g
let h2 x = x |> f |> g

Here, h2会编译得很好,但是h1不会,抱怨价值限制。


在实践中,这三种方式之间的选择通常取决于可读性和便利性。这些本质上并不比其他更好。当我编写代码时,我通常根据自己的喜好进行选择。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

F#:管道与作曲与......作曲? 的相关文章

  • 如何从复合泛型类型中检索值?

    如何从泛型中检索值 具体来说 我正在尝试以下操作 Test let result Validate goodInput How to access record let request getRequest result 这是代码 type
  • F#:将字符串选项转换为字符串的最短方法

    目标是转换一个string option这是通过一些很好的类型计算得出的一个简单的string然后可以传递到 UI printf URL 其他只想要一个字符串并且对选项类型一无所知的东西 None应该变成空字符串 显而易见的方法是做一个ma
  • 不可变数据结构性能

    我不明白作为一个集合的东西怎么可能是不可变的并且仍然具有可接受的性能 根据我在 F Sets 中读到的内容 内部使用红黑树作为其实现 如果每次我们想要向红黑树添加新内容时 我们基本上都必须重新创建它 那么它如何才能具有良好的性能呢 我在这里
  • 类型 x 比值更难访问

    这是我的代码的抽象 module RootModule module private SubModule I want everything in this module to be inaccessible from outside th
  • 定义具有多种消息类型的消息传递域

    到目前为止 我见过的大多数 F 消息传递示例都使用 2 4 种消息类型 并且能够利用模式匹配将每条消息定向到其正确的处理函数 对于我的应用程序 由于处理和所需参数的不同性质 我需要数百种独特的消息类型 到目前为止 每个消息类型都是其自己的记
  • 如何在 F# 列表和 F# 元组之间进行转换?

    有没有办法在 F List 和 F Tuple 之间进行转换 例如 1 2 3 gt 1 2 3 1 2 3 4 gt 1 2 3 4 我需要两个函数来做到这一点 let listToTuple list let tupleToList t
  • 双前向/后向管道操作符是否有记录?

    我记得读过有关双管道运算符的内容 gt 和 Example let print a b sprintf O O a b 1 2 gt print val it string 1 2 双 向前 向后 管道运算符记录在以下列表中MSDN 上的
  • 如何搭建Windows Phone开发环境并使用F#开发应用程序?

    我已经下载了Windows Phone开发工具 但我不知道如何使用F 来开发应用程序 目前是C 将 F 和 Windows Phone 模板安装到 Visual Studio 中可以让生活变得更轻松 如果您打开 Visual Studio
  • 如何更改 Rx Builder 实现来修复堆栈溢出异常?

    我正在尝试提出一个 Rx Builder 以在 F 计算表达式语法中使用反应式扩展 我该如何修复它 以免堆栈崩溃 就像下面的 Seq 例子一样 是否有计划提供 RxBuilder 的实现作为响应式扩展的一部分或作为 NET Framewor
  • F# 2010 Seq.generate_using

    Visual Studio 2010 中的 Seq generate using 是否有替代 解决方法 FSharp PowerPack dll 不适用于 2010 AFAIK 很抱歉 2010 年的 PowerPack 尚未上市 我不记得
  • F# 参数传递

    我一直认为 F 有两种不同的方式来传递参数 柯里化风格和元组风格 这实际上是正确的吗 是不是很简单一种风格 柯里化风格和参数可以是简单值或元组 e g someFunc a b 这不是一个函数吗one咖喱风格的参数恰好是一个元组 因此允许我
  • 在 IEnumerable 上使用 Seq 函数 [重复]

    这个问题在这里已经有答案了 我正在尝试在 IEnumerable 上应用 Seq 函数 更具体地说 它是System Windows Forms HtmlElementCollection它实现了ICollection and IEnume
  • F# 在类型提供程序内的类型扩展函数中生成类型

    我有以下问题 在我的类型提供程序中 我需要使用一个返回此泛型类型实例的方法来扩展我之前定义的泛型类型 我的意思是 假设我们有 type receiveType lt a gt class val Next int val Type stri
  • F# 中类型约束的顺序

    这适用于 F 4 0 type Something lt a b when b gt seq lt b gt gt 这不会 type Something lt b when b gt seq lt b gt a gt 类型名称中出现意外的符
  • F# 类型提供程序与 Lisp 宏

    我一直在阅读有关 F 3 0 类型提供程序的内容 例如here http msdn microsoft com en us library hh156509 aspx 并且它们似乎基于一种编译时代码生成 在这方面我想知道它们与 Lisp 宏
  • 使用 SqlBulkCopy 和 F# 在 SQL 中导出矩阵

    我想将大量数据从 F 传输到 SQL 表 基本上我的 F 代码创建了一个三列矩阵 UserID ProductID and price 和N行 我想将其 复制 粘贴 到数据库中 我尝试了多种选择 但最终 从 F 传输数据非常慢 10000
  • 将 Foq 与 F# 函数类型结合使用

    例如 我使用 F 类型定义来防止函数之间的硬依赖 type IType1 int gt int type IType2 int gt string let func1 i int int i i let func2 i int string
  • 从 C# 调用高阶 F# 函数

    给定 F 高阶函数 在参数中采用函数 let ApplyOn2 f int gt int f 2 和 C 函数 public static int Increment int a return a 我怎么打电话ApplyOn2 with I
  • F# nameof 运算符不是一等函数

    我正在使用 F 4 7
  • 将 C# 代码转换为 F#(if 语句)

    我想知道如何转换此代码逐行从 C 到 F 我不想使用任何类型的 F 习惯用法或类似的东西 我想了解如何直接映射C 的构造到 F 这是 C 代码 requires l Length gt 0 int GetMinimumValue List

随机推荐