23

这是一个类似的C#问题的不加掩饰的尝试。

那么您最喜欢的 F# 隐藏(或不隐藏)功能是什么?

到目前为止,我使用的大多数功能都没有完全隐藏,但非常令人耳目一新。与 C# 或 VB.NET 相比,重载运算符是多么微不足道。

Async<T>帮助我剃掉了一些真正丑陋的代码。

我对这门语言还是很陌生,所以很高兴了解野外使用的其他功能。

4

11 回答 11

29

用户定义的数字文字可以通过提供一个模块来定义,该模块的名称以开头NumericLiteral并定义了某些方法(FromZeroFromOne等)。

LanguagePrimitives.GenericZero特别是,您可以使用它为调用and提供更易读的语法LanguagePrimitives.GenericOne

module NumericLiteralG = begin
  let inline FromZero() = LanguagePrimitives.GenericZero
  let inline FromOne() = LanguagePrimitives.GenericOne
end

let inline genericFactorial n =
  let rec fact n = if (n = 0G) then 1G else n * (fact (n - 1G))
  fact n

let flt = genericFactorial 30.
let bigI = genericFactorial 30I
于 2009-12-04T12:43:32.050 回答
10

F# 有一个很少使用的功能,称为“签名文件”。您可以拥有一个充满公共类型/方法/模块/功能的大实现文件,但随后您可以通过签名文件隐藏并选择性地将该功能公开给程序的后续版本。也就是说,签名文件充当一种屏幕/过滤器,使您能够使实体“对该文件公开”但“对程序的其余部分保密”。

我觉得这是 .Net 平台上的一个非常杀手级的功能,因为用于这种封装的唯一其他/先前工具是程序集。如果您有一个包含一些相关类型的小组件,希望能够看到彼此的内部详细信息,但不希望这些类型将所有这些位公开给所有人,您该怎么办?好吧,你可以做两件事:

  1. 您可以将该组件放在单独的程序集中,并使这些类型共享的成员为“内部”,并使您希望其他人看到的狭窄部分为“公共”,或者
  2. 您只需将内部内容标记为“内部”,但将这些类型留在庞大的程序集中,并希望程序集中的所有其他代码选择不调用那些仅标记为“内部”的成员,因为需要另一种类型才能看到它.

以我的经验,在大型软件项目中,每个人都总是做#2,因为出于各种原因,#1 不是初学者(人们不想要 50 个小程序集,他们想要 1 个或 2 个或 3 个大程序集,对于其他可能 -与我提出的封装点无关的充分理由(除此之外:每个人都提到 ILMerge,但没有人使用它))。

所以你选择了选项#2。然后一年后,你终于决定重构那个组件,你发现在过去的一年里,其他 17 个地方现在调用了那个“内部”方法,而这个方法实际上只适用于另一种类型的调用,使它真的很难考虑到这一点,因为现在每个人都依赖于这些实现细节。真可惜。

关键是,在 .Net 中没有创建中等大小的程序集内封装范围/边界的好方法。很多时候“内部”太大而“私人”太小。

...直到 F#。使用 F# 签名文件,您可以通过在实现文件中将一堆东西标记为公共来创建“此源代码文件”的封装范围,因此文件中的所有其他代码都可以看到它并参与其中,然后使用隐藏所有细节的签名文件期望组件向世界其他地方公开的狭窄公共接口。这是快乐的。在一个文件中定义三个高度相关的类型,让他们看到彼此的实现细节,但只将真正公开的东西暴露给其他人。赢!

签名文件可能不是组件内封装边界的理想功能,但它们是我所知道的唯一此类功能,因此我像海洋中的救生筏一样紧紧抓住它们。

TL;博士

复杂性是敌人。封装边界是对付这个敌人的武器。“私有”是一个很好的武器,但有时太小而无法应用,“内部”通常太弱,因为太多代码(整个程序集和所有 InternalsVisibleTo 的)可以看到内部的东西。F# 提供的范围大于“类型专用”但小于“整个程序集”,这非常有用。

于 2009-12-04T04:33:29.540 回答
9

我想知道如果你添加会发生什么

<appSettings>
  <add key="fsharp-navigationbar-enabled" value="true" />
</appSettings>

到你的 devenv.exe.config 文件?(使用风险自负。)

于 2010-10-06T05:47:04.730 回答
8

传递--warnon:1182给编译器会打开关于未使用变量的警告;以下划线开头的变量名是免疫的。

于 2010-06-29T06:28:06.313 回答
7

代数数据类型的自动生成比较函数(基于字典顺序)是一个相对未知的好特性;看

http://lorgonblog.spaces.live.com/blog/cns!701679AD17B6D310!548.entry

例如。

于 2008-10-17T10:46:51.873 回答
6

是的,F# 没有任何“隐藏”功能,但它确实在简单的语言中包含了很多功能。该语言的一个鲜为人知的特性是,尽管 F# 是静态类型的,但您基本上可以启用鸭子类型。

于 2008-10-09T05:19:22.283 回答
6

看到这个问题

F# 运算符“?”

有关问号运算符的信息,以及它如何提供基本语言机制来构建类似于 C# 中“动态”的功能。

于 2009-07-23T07:44:30.603 回答
5

不是真的隐藏,但作为一个非 ML 的人,这让我很长时间没有想到:

模式匹配可以任意深入地分解为数据结构。

这是一个 [令人难以置信的任意] 嵌套元组示例;这适用于列表或联合或嵌套值的任何组合:

let listEven =
  "Manipulating strings can be intriguing using F#".Split ' '
  |> List.ofArray
  |> List.map (fun x -> (x.Length % 2 = 0, x.Contains "i"), x)
  |> List.choose 
     ( function (true, true), s -> Some s 
              | _, "F#"         -> Some "language" 
              | _               -> None ) 
于 2010-06-29T14:33:16.847 回答
3

将 F# 用作实用程序脚本语言可能不受欢迎。F# 爱好者往往是 Quant。有时您希望备份 MP3(或数十个数据库服务器)的功能比批处理功能更强大。我一直在寻找 jscript / vbscript 的现代替代品。最近,我使用了 IronPython,但 F# 可能更完整,.NET 交互也不那么麻烦。

我喜欢用于娱乐价值的咖喱函数。向至少三个 WTF 的纯过程/OOP 程序显示柯里化函数。不过,从这里开始是获得 F# 转换的不好方法:)

于 2009-05-10T20:23:10.333 回答
2

泛型类型的内联运算符可以有不同的泛型约束:

type 'a Wrapper = Wrapper of 'a with
  static member inline (+)(Wrapper(a),Wrapper(b)) = Wrapper(a + b)
  static member inline Exp(Wrapper(a)) = Wrapper(exp a)

let objWrapper = Wrapper(obj())
let intWrapper = (Wrapper 1) + (Wrapper 2)
let fltWrapper = exp (Wrapper 1.0)

(* won''t compile *)
let _ = exp (Wrapper 1)
于 2009-12-04T12:31:45.913 回答
1

没有隐藏功能,因为 F# 处于设计模式。我们所拥有的只是技术预览,每两个月更改一次。

http://research.microsoft.com/fsharp/

于 2008-10-08T07:14:32.393 回答