我正在尝试重构一些现有代码into a more monodic approach。现有代码包含接口b*-
和数字IXInterface
和int
。默认情况下,数字已经bool
,接口将其作为属性gettor,但Zero
和bool
没有。一种方法是在界面中包含bool和string,但这很麻烦。
我认为如果F#语言设法扩展数字的类型,也许我也可以为字符串和bool做我喜欢的特定情况。
string
以上编译很好,只要我不尝试使用字符串或bools:
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
错误是清楚正确的(我有一个扩展方法,由于显而易见的原因无法识别),我只是不知道一种非侵入性的方法来摆脱它:
失败,“bool类型不支持运营商'get_Zero' 失败,“类型字符串不支持运算符'get_Zero'
答案 0 :(得分:5)
F#设法使用静态优化扩展数值类型,静态优化是在F#核心库外部禁用的功能。
AFAIK获得类似机制的唯一方法是使用重载和静态成员约束。
你确实想要做的事情已经在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
不是幺半群的最佳名称,请记住乘法下的第一个也是幺半群{{1}已经在F#核心库中用于通用数字。
但老实说,如果你正朝着这个方向前进,我强烈建议你考虑一下这个库,因为在扩展已经解决的代码时你会发现很多问题,你可以免费获得其他类似monoid的函数,比如{{1}和get_Zero
,你的类型会得到更好的签名。