获取或实现 String.Zero 和 bool.Zero 一般用于幺半群
Getting or implementing String.Zero and bool.Zero generically for use with monoids
我正在尝试重构一些现有代码 into a more monodic approach。现有代码包含接口 IXInterface
和数字 int
和 bool
。默认情况下,数字已经有 Zero
,接口将其作为 属性 gettor,但 bool
和 string
没有。一种解决方法是将 bool 和 string 包装在一个接口中,但这很麻烦。
我想如果 F# 语言能够扩展数字类型,也许我也可以针对我的特定情况对字符串和布尔值进行扩展。
module MyZero =
let inline get_zero () : ^a = ((^a) : (static member get_Zero : unit -> ^a)())
type System.String with
static member get_Zero() = System.String.Empty
type XR<'T when 'T : (static member get_Zero : unit -> 'T)> =
| Expression of (SomeObj -> 'T)
| Action of (int -> 'T)
| Value of 'T
| Empty
member inline this.Execute(x: SomeObj) : 'T =
match this with
| Value(v) -> v
| Expression(ex) -> ex x
| Action(a) -> a x.GetLocation
| Empty -> get_zero()
static member map f x=
match x with
| XR.Empty -> XR.Empty
| XR.Value v -> XR.Value <| f v
| XR.Action p -> XR.Action <| fun v -> f (p v)
| XR.Expression e -> XR.Expression <| fun x -> f (e x)
// etc
上面的编译很好,只要我不尝试将它与字符串或布尔一起使用:
type WihtBool = XR<int> // succeeds
type WihtBool = XR<IXInterface> // succeeds
type WihtBool = XR<bool> // fails
type WithString = XR<string> // fails
错误明确且正确(我有一个扩展方法,由于明显的原因无法识别),我只是不知道摆脱它的非侵入性方法:
fails with "the type bool does not support the operator 'get_Zero'
fails with "the type string does not support the operator 'get_Zero'
F# 设法使用静态优化扩展数字类型,这是在 F# 核心库之外禁用的功能。
据我所知,获得类似机制的唯一方法是使用重载和静态成员约束。
事实上,您正在尝试做的事情已经在 F#+
中实现了
#nowarn "3186"
#r @"FsControl.Core.dll"
#r @"FSharpPlus.dll"
open FSharpPlus
let x:string = mempty()
// val x : string = ""
type Boo = Boo with
static member Mempty() = Boo
let y:Boo = mempty()
// val y : Boo = Boo
它的工作原理与 F# 数学运算符相同,其中任何参数的类型都可以满足静态约束。
这里是 source code 的一部分,让这一切变得神奇。
目前缺少 bool
的一个实例,但您可以添加一个建议它的问题或拉取请求,它将是一个(或两个)行。
无论如何,如果您想获得此功能,请尝试此快速独立代码:
type Mempty =
static member ($) (_:Mempty, _:string) = ""
static member ($) (_:Mempty, _:bool) = false
let inline mempty() :'t = Unchecked.defaultof<Mempty> $ Unchecked.defaultof<'t>
let x:string = mempty()
// val x : string = ""
let y:bool = mempty()
// val y : bool = false
type Boo = Boo with
static member ($) (_:Mempty, _:Boo) = Boo
let z:Boo = mempty()
// val z : Boo = Boo
您可以将 Mempty
重命名为 get_Zero
但我认为 get_Zero
不是幺半群的最佳名称,请记住乘法下的第一个也是一个幺半群并且 get_Zero
已在 F# 核心库中用于通用数字。
但老实说,如果你朝这个方向前进,我强烈建议你考虑那个库,因为在扩展你的代码时你可能会发现很多问题已经解决了,你可以免费获得其他与幺半群相关的函数,比如 mconcat
和 mfold
并且你会在你的类型上获得更好的签名。
我正在尝试重构一些现有代码 into a more monodic approach。现有代码包含接口 IXInterface
和数字 int
和 bool
。默认情况下,数字已经有 Zero
,接口将其作为 属性 gettor,但 bool
和 string
没有。一种解决方法是将 bool 和 string 包装在一个接口中,但这很麻烦。
我想如果 F# 语言能够扩展数字类型,也许我也可以针对我的特定情况对字符串和布尔值进行扩展。
module MyZero =
let inline get_zero () : ^a = ((^a) : (static member get_Zero : unit -> ^a)())
type System.String with
static member get_Zero() = System.String.Empty
type XR<'T when 'T : (static member get_Zero : unit -> 'T)> =
| Expression of (SomeObj -> 'T)
| Action of (int -> 'T)
| Value of 'T
| Empty
member inline this.Execute(x: SomeObj) : 'T =
match this with
| Value(v) -> v
| Expression(ex) -> ex x
| Action(a) -> a x.GetLocation
| Empty -> get_zero()
static member map f x=
match x with
| XR.Empty -> XR.Empty
| XR.Value v -> XR.Value <| f v
| XR.Action p -> XR.Action <| fun v -> f (p v)
| XR.Expression e -> XR.Expression <| fun x -> f (e x)
// etc
上面的编译很好,只要我不尝试将它与字符串或布尔一起使用:
type WihtBool = XR<int> // succeeds
type WihtBool = XR<IXInterface> // succeeds
type WihtBool = XR<bool> // fails
type WithString = XR<string> // fails
错误明确且正确(我有一个扩展方法,由于明显的原因无法识别),我只是不知道摆脱它的非侵入性方法:
fails with "the type bool does not support the operator 'get_Zero'
fails with "the type string does not support the operator 'get_Zero'
F# 设法使用静态优化扩展数字类型,这是在 F# 核心库之外禁用的功能。
据我所知,获得类似机制的唯一方法是使用重载和静态成员约束。
事实上,您正在尝试做的事情已经在 F#+
中实现了#nowarn "3186"
#r @"FsControl.Core.dll"
#r @"FSharpPlus.dll"
open FSharpPlus
let x:string = mempty()
// val x : string = ""
type Boo = Boo with
static member Mempty() = Boo
let y:Boo = mempty()
// val y : Boo = Boo
它的工作原理与 F# 数学运算符相同,其中任何参数的类型都可以满足静态约束。
这里是 source code 的一部分,让这一切变得神奇。
目前缺少 bool
的一个实例,但您可以添加一个建议它的问题或拉取请求,它将是一个(或两个)行。
无论如何,如果您想获得此功能,请尝试此快速独立代码:
type Mempty =
static member ($) (_:Mempty, _:string) = ""
static member ($) (_:Mempty, _:bool) = false
let inline mempty() :'t = Unchecked.defaultof<Mempty> $ Unchecked.defaultof<'t>
let x:string = mempty()
// val x : string = ""
let y:bool = mempty()
// val y : bool = false
type Boo = Boo with
static member ($) (_:Mempty, _:Boo) = Boo
let z:Boo = mempty()
// val z : Boo = Boo
您可以将 Mempty
重命名为 get_Zero
但我认为 get_Zero
不是幺半群的最佳名称,请记住乘法下的第一个也是一个幺半群并且 get_Zero
已在 F# 核心库中用于通用数字。
但老实说,如果你朝这个方向前进,我强烈建议你考虑那个库,因为在扩展你的代码时你可能会发现很多问题已经解决了,你可以免费获得其他与幺半群相关的函数,比如 mconcat
和 mfold
并且你会在你的类型上获得更好的签名。