F# 静态解析的类型成员约束无法识别系统类型的扩充
为了更好地掌握F#,更好地理解Suave.io的工作原理,我一直在尝试创建一些可重用的函数/操作符来组合函数。我知道Suave实际上实现了它的>=>操作符,专门用于异步选项,但我认为尝试并推广它会很有趣 下面的代码是受太多来源的启发而产生的,它适用于我自己定义的类型,但我不能使它适用于系统类型。尽管Nullable和Option的类型扩展编译得很好,但它们不会被识别为与bind函数中的成员约束匹配 当我无法让它为Option工作时,我曾希望这可能是因为Option在F#中是特殊的,这就是为什么我尝试使用Nullable,但遗憾的是,没有雪茄 fsi的相关错误和输出在注释的下面代码中 任何帮助都将不胜感激 谢谢, 约翰F# 静态解析的类型成员约束无法识别系统类型的扩充,f#,inline,F#,Inline,为了更好地掌握F#,更好地理解Suave.io的工作原理,我一直在尝试创建一些可重用的函数/操作符来组合函数。我知道Suave实际上实现了它的>=>操作符,专门用于异步选项,但我认为尝试并推广它会很有趣 下面的代码是受太多来源的启发而产生的,它适用于我自己定义的类型,但我不能使它适用于系统类型。尽管Nullable和Option的类型扩展编译得很好,但它们不会被识别为与bind函数中的成员约束匹配 当我无法让它为Option工作时,我曾希望这可能是因为Option在F#中是特殊的,这就是为什么我
开放系统
让内联绑定(f:^f)(v:^v)=
(^v:(静态成员绑定:^f*^v->^r)(f,v))
//我不想在doBind中使用元组,但我已经
//无法使多参数成员约束生效
让内联(>=>)f g=f>>(绑定g)
//实例与结果
类型公共结果=
|a的成功
|“b”的错误
键入带有
静态成员内联公共多bind(f,v)=
匹配
|成功s->f s
|错误e->错误e
设rF a=如果a>0,则成功,否则错误“小于0”
设rG a=如果a<10,则成功,否则错误“大于9”
设rFG=rF>=>rG
//val rFG:(整数->结果)
//>rFG 0;;
//val it:结果=错误“小于0”
//>rFG 1;;
//val it:Result=Success 1
//>rFG 10;;
//val it:结果=错误“大于9”
//>rFG 9;;
//val it:结果=成功9
//因此,它按照预期的结果工作
//可为null的示例
键入Nullable'T)和'T:struct以及'T:>ValueType>with
静态成员内联公共doBind(f,v:Nullable with
静态构件直列多臂(f,v)=
匹配
|一些s->f s
|无->无
设a=如果a>0,则有些a其他a无
设oG a=如果a<10,则有些a其他a无
设oFG=oF>=>oG
//错误FS0001:类型“int option”不支持运算符“doBind”
为什么在静态成员约束中不考虑扩展方法是一个已经被问了很多次的问题,并且肯定会一直被问到,直到该特性在F#编译器中实现为止
请参阅,其中包含指向其他相关问题的链接,以及指向为支持此功能必须在F#编译器中执行的操作的详细说明的链接
现在,对于您的具体案例,这里提到的解决方法解决了您的问题,并且已经在中实现了
代码如下:
#nowarn "3186"
#r "FsControl.dll"
open FsControl.Operators
// Example with Result
type public Result<'a,'b> =
| Success of 'a
| Error of 'b
type public Result<'a,'b> with
static member Return v = Success v
static member Bind (v, f) =
match v with
| Success s -> f s
| Error e -> Error e
let rF a = if a > 0 then Success a else Error "less than 0"
let rG a = if a < 10 then Success a else Error "greater than 9"
let rFG = rF >=> rG
// val rFG : (int -> Result<int,string>)
rFG 0
//val it : Result<int,string> = Error "less than 0"
rFG 1
//val it : Result<int,string> = Success 1
rFG 10
//val it : Result<int,string> = Error "greater than 9"
rFG 9
//val it : Result<int,string> = Success 9
// So it works as expected for Result
// Example with Option
let oF a = if a > 0 then Some a else None
// val oF : a:int -> int option
let oG a = if a < 10 then Some a else None
// val oG : a:int -> int option
let oFG = oF >=> oG
// val oFG : (int -> int option)
oFG 0
// val it : int option = None
oFG 1
// val it : int option = Some 1
然后,您可以运行示例,而无需编写任何绑定或返回
您可能想知道为什么没有可为
Nullable
的示例,这仅仅是因为Nullable
不是monad,它只对值类型有效,而函数不是值类型,所以对于相同的功能,最好坚持使用选项。静态解析的类型约束不考虑扩展成员。J这不是F#,period的一个特性。正如Fyodor所提到的,这是不受支持的。虽然我认为这实际上是F#的一个很好的扩展,但我有点好奇你对它有什么想法?我觉得这很好,因为它非常简单,也不太抽象,所以概括操作符听起来不像是要讨论的东西wards better F#code-当然,只是探索它很有趣。@FyodorSoikin谢谢,这就解释了它。多么烦人的限制,已经投了3票:)@JJJ我不确定-你可以稍微扩展F#静态约束(就像FsControl一样),但我认为这不是它们的设计目的。[rant]FsControl是一个惊人的成就,但我不会在实践中真正使用它,因为它接近于粗糙的边缘,而且通常对原始问题有更惯用的解决方案。换句话说,我认为从一种语言(C++模板或Haskell类型类)中获取概念并尝试在另一种语言(F#)中使用它们并不总是导致非常干净的代码。别担心,我是个务实的人。我只是喜欢探索语言。也许如果F#有一个更强大、更一致的元编程故事,人们就不会试图从其他地方引进东西。谢谢你的详细回答。我将特别检查链接和FsControl。@事实上,JJJ甚至不需要在首选项上实现成功(请参阅更新的答案)。无论如何,这肯定是一个好主意,因为您将重用所有现有功能并增加与其他库的兼容性。
#nowarn "3186"
#r "FsControl.dll"
open FsControl.Operators
// Example with Result
type public Result<'a,'b> =
| Success of 'a
| Error of 'b
type public Result<'a,'b> with
static member Return v = Success v
static member Bind (v, f) =
match v with
| Success s -> f s
| Error e -> Error e
let rF a = if a > 0 then Success a else Error "less than 0"
let rG a = if a < 10 then Success a else Error "greater than 9"
let rFG = rF >=> rG
// val rFG : (int -> Result<int,string>)
rFG 0
//val it : Result<int,string> = Error "less than 0"
rFG 1
//val it : Result<int,string> = Success 1
rFG 10
//val it : Result<int,string> = Error "greater than 9"
rFG 9
//val it : Result<int,string> = Success 9
// So it works as expected for Result
// Example with Option
let oF a = if a > 0 then Some a else None
// val oF : a:int -> int option
let oG a = if a < 10 then Some a else None
// val oG : a:int -> int option
let oFG = oF >=> oG
// val oFG : (int -> int option)
oFG 0
// val it : int option = None
oFG 1
// val it : int option = Some 1
type Result<'a, 'b> = Choice<'a, 'b>
let Success x :Result<'a, 'b> = Choice1Of2 x
let Error x :Result<'a, 'b> = Choice2Of2 x
let (|Success|Error|) = function Choice1Of2 x -> Success x | Choice2Of2 x -> Error x