从F#DU访问特定案例

Aka*_*ash 4 f# discriminated-union

假设我有以下DU:

type Something =
| A of int
| B of string * int
Run Code Online (Sandbox Code Playgroud)

现在我在这样的函数中使用它:

let UseSomething = function
| A(i) -> DoSomethingWithA i
| B(s, i) -> DoSomethingWithB s i
Run Code Online (Sandbox Code Playgroud)

这是有效的,但我必须解构DU才能将它传递给DoSomethingWith*函数.尝试将DoSomethingWithA定义为:我觉得很自然:

let DoSomethingWithA (a: Something.A) = ....
Run Code Online (Sandbox Code Playgroud)

但编译器抱怨未定义类型A.

似乎完全符合F#的哲学,希望将参数限制为Something.A,而不仅仅是任何旧的int,所以我只是以错误的方式去做?

pad*_*pad 5

需要注意的重要一点是,AB是的构造相同类型Something.因此,如果您尝试单独使用AB案例,您将获得无穷无尽的模式匹配警告.

IMO,解构所有DU的情况是一个好主意,因为它是类型安全的,并迫使你考虑处理那些甚至你不想要的情况.如果您必须以相同的方式重复解构DU,则可能会出现此问题.在这种情况下,在DU上定义mapfold功能可能是一个好主意:

let mapSomething fa fb = function
| A(i) -> fa i
| B(s, i) -> fb s i
Run Code Online (Sandbox Code Playgroud)

请参考@Brian的优秀Catamorphism系列来了解DUs上的折叠.

那也说你的榜样很好.解构后你真正处理的是什么stringint价值观.

您可以使用Active Patterns分别使用两种情况:

let (|ACase|) = function A i -> i | B _ -> failwith "Unexpected pattern B _"
let (|BCase|) = function B(s, i) -> (s, i) | A _ -> failwith "Unexpected pattern A _"

let doSomethingWithA (ACase i) = ....
Run Code Online (Sandbox Code Playgroud)

但推断的类型doSomethingWithA仍然相同,并且在传递B _给函数时会出现异常.所以做IMO是错误的.

  • 后者是真的.前者是OOP观点中的实施细节,可能相关也可能不相关. (2认同)