展开 F# 单例区分联合元组类型
Unwrap F# single-case discriminated union tuple type
我们可以像type Address = Address of string
一样使用像
这样的解包函数来解包类型
let unwrapAddress (Address a) = a
let addr = Address "sdf"
let str = unwrapAddress addr
所以 str
将是 string
类型,但如果有类似这种方法的类型将不起作用:
type Composite = Composite of integer:int * someStr:string
let unwrap (Composite c) = c
会产生错误
let unwrap (Composite c) = c;;
------------^^^^^^^^^^^
error FS0019: This constructor is applied to 1 argument(s) but expects 2
我能否以某种方式将复合类型解包为简单的元组?
这些都对我有用。这是你的 matching 语法,你会发现它最常与匹配语句一起使用,但它在 l.h.s 上。的任务。最初,这可能最适合元组,但您可以将其用于任何结构。
let (a,b) = (1,2)
let (x,_) = (4,5)
另外两个有趣的尝试:
let (head::tail) = [1;2;3;4]
FSI 响应警告 FS0025:此表达式的模式匹配不完整。例如,值“[]”可能表示模式未涵盖的情况。
"That's true,"你大声推理。 "I should express it as a match and include an empty list as a possibility"。最好将这些类型的警告冒充成完全真实的错误(参见:warn as error 例如 --warnaserror+:25)。不要忽视他们。通过习惯或编译器强制方法解决它们。单个案例的歧义为零,因此开始编码。
更有用+有趣的是 l.h.s 上的匹配语法。的功能分配。这很酷。精髓的函数,可以把里面的东西拆开,然后一步一步对内部进行操作。
let f (Composite(x,y)) = sprintf "Composite(%i,%s)" x y
f (Composite(1,"one"))
> val it : string = "Composite(1,one)"
关于您的代码:
type Address = Address of string //using unwrapping function like
let unwrapAddress (Address a) = a
let addr = Address "sdf"
let str = unwrapAddress addr
type Composite = Composite of integer:int * someStr:string
let unwrap (Composite(c,_)) = c
let cval = Composite(1,"blah")
unwrap cval
解决方法:
let xy = Composite(1,"abc") |> function (Composite(x,y))->(x,y)
...但更好的方法是,假设您想保留单个案例 DU 的命名元素...
let (|Composite|) = function | Composite(x,y)->(x,y)
let unwrap (Composite(x)) = x
let unwrap2 (Composite(x,y)) = (x,y)
...不是严格通过单例DU分解,而是通过单例Active Pattern
分解
最后,您可以将方法附加到复合结构...
module Composite =
let unwrap = function | Composite(x,y)->(x,y)
关于使用此技术的最佳讨论之一已经结束 here
此外,检查 unwrap 给我们的签名:一个接受 Composite(斜体)和 returns int(粗体)的函数
签名 -- val unwrap : Composite -> int
在你的情况下,你可以这样写:
type Composite = Composite of int * string
let unwrap (Composite (a, b)) = a, b
对应于:
let unwrap x =
match x with
| Composite (a, b) -> a, b
这里发生的事情是 F# 允许您使用任意复杂的模式匹配内联解构函数参数。在介绍单例DU时经常提到这一点,但很少得出结论,这导致人们认为单例DU在某种程度上是特殊的。
其实当你有多个case的时候就可以用了(只要每个case绑定的是同一组变量):
type Composite = Composite of int * string | JustString of string
let unwrapString (Composite (_, s) | JustString s) = s
但大多数时候,您会在更简单的类型上进行模式匹配,例如元组:
let f (a, b, c) = ...
或者更奇怪的是:
let f () = ...
此处 ()
是单位类型的单个值的模式匹配 - 而不是通常描述的某种 "visual marker for a parameterless function"。
您将类型定义为具有命名字段的单大小写区分联合:
type Composite = Composite of integer:int * someStr:string
这样定义的时候,并集的字段就不是简单的元组了。它们以特殊方式处理,例如,名称在编译代码中用作 属性 名称。模式匹配不会自动将元素转换为元组,因此您必须单独打开它们:
let unwrap (Composite(i, s)) = i, s
但是,您也可以定义单例联合,其中字段是普通元组。 (请注意,您需要将元组类型括起来 - 否则,它最终也会以特殊方式处理,除了这些项目将被编译为 Item1
和 Item2
。)
type Composite = Composite of (int * string)
使用此定义,您的 unwrap
函数将正常工作并提取元组值:
let unwrap (Composite c) = c
您也可以使用嵌套模式来获取数字和字符串,如前例所示:
let unwrap (Composite(i, s)) = i, s
根据您是写 A of (T1 * T2)
还是写 A of T1 * T2
其行为有所不同这一事实有点微妙 - 可能需要区分这两者,以便编译器知道是否将字段编译为两个单独的字段或类型为 System.Tuple<T1, T2>
的一个字段。我无法想象在任何其他情况下差异会很重要。
我们可以像type Address = Address of string
一样使用像
let unwrapAddress (Address a) = a
let addr = Address "sdf"
let str = unwrapAddress addr
所以 str
将是 string
类型,但如果有类似这种方法的类型将不起作用:
type Composite = Composite of integer:int * someStr:string
let unwrap (Composite c) = c
会产生错误
let unwrap (Composite c) = c;;
------------^^^^^^^^^^^
error FS0019: This constructor is applied to 1 argument(s) but expects 2
我能否以某种方式将复合类型解包为简单的元组?
这些都对我有用。这是你的 matching 语法,你会发现它最常与匹配语句一起使用,但它在 l.h.s 上。的任务。最初,这可能最适合元组,但您可以将其用于任何结构。
let (a,b) = (1,2)
let (x,_) = (4,5)
另外两个有趣的尝试:
let (head::tail) = [1;2;3;4]
FSI 响应警告 FS0025:此表达式的模式匹配不完整。例如,值“[]”可能表示模式未涵盖的情况。
"That's true,"你大声推理。 "I should express it as a match and include an empty list as a possibility"。最好将这些类型的警告冒充成完全真实的错误(参见:warn as error 例如 --warnaserror+:25)。不要忽视他们。通过习惯或编译器强制方法解决它们。单个案例的歧义为零,因此开始编码。
更有用+有趣的是 l.h.s 上的匹配语法。的功能分配。这很酷。精髓的函数,可以把里面的东西拆开,然后一步一步对内部进行操作。
let f (Composite(x,y)) = sprintf "Composite(%i,%s)" x y
f (Composite(1,"one"))
> val it : string = "Composite(1,one)"
关于您的代码:
type Address = Address of string //using unwrapping function like
let unwrapAddress (Address a) = a
let addr = Address "sdf"
let str = unwrapAddress addr
type Composite = Composite of integer:int * someStr:string
let unwrap (Composite(c,_)) = c
let cval = Composite(1,"blah")
unwrap cval
解决方法:
let xy = Composite(1,"abc") |> function (Composite(x,y))->(x,y)
...但更好的方法是,假设您想保留单个案例 DU 的命名元素...
let (|Composite|) = function | Composite(x,y)->(x,y)
let unwrap (Composite(x)) = x
let unwrap2 (Composite(x,y)) = (x,y)
...不是严格通过单例DU分解,而是通过单例Active Pattern
分解最后,您可以将方法附加到复合结构...
module Composite =
let unwrap = function | Composite(x,y)->(x,y)
关于使用此技术的最佳讨论之一已经结束 here
此外,检查 unwrap 给我们的签名:一个接受 Composite(斜体)和 returns int(粗体)的函数
签名 -- val unwrap : Composite -> int
在你的情况下,你可以这样写:
type Composite = Composite of int * string
let unwrap (Composite (a, b)) = a, b
对应于:
let unwrap x =
match x with
| Composite (a, b) -> a, b
这里发生的事情是 F# 允许您使用任意复杂的模式匹配内联解构函数参数。在介绍单例DU时经常提到这一点,但很少得出结论,这导致人们认为单例DU在某种程度上是特殊的。
其实当你有多个case的时候就可以用了(只要每个case绑定的是同一组变量):
type Composite = Composite of int * string | JustString of string
let unwrapString (Composite (_, s) | JustString s) = s
但大多数时候,您会在更简单的类型上进行模式匹配,例如元组:
let f (a, b, c) = ...
或者更奇怪的是:
let f () = ...
此处 ()
是单位类型的单个值的模式匹配 - 而不是通常描述的某种 "visual marker for a parameterless function"。
您将类型定义为具有命名字段的单大小写区分联合:
type Composite = Composite of integer:int * someStr:string
这样定义的时候,并集的字段就不是简单的元组了。它们以特殊方式处理,例如,名称在编译代码中用作 属性 名称。模式匹配不会自动将元素转换为元组,因此您必须单独打开它们:
let unwrap (Composite(i, s)) = i, s
但是,您也可以定义单例联合,其中字段是普通元组。 (请注意,您需要将元组类型括起来 - 否则,它最终也会以特殊方式处理,除了这些项目将被编译为 Item1
和 Item2
。)
type Composite = Composite of (int * string)
使用此定义,您的 unwrap
函数将正常工作并提取元组值:
let unwrap (Composite c) = c
您也可以使用嵌套模式来获取数字和字符串,如前例所示:
let unwrap (Composite(i, s)) = i, s
根据您是写 A of (T1 * T2)
还是写 A of T1 * T2
其行为有所不同这一事实有点微妙 - 可能需要区分这两者,以便编译器知道是否将字段编译为两个单独的字段或类型为 System.Tuple<T1, T2>
的一个字段。我无法想象在任何其他情况下差异会很重要。