小编Ale*_*kol的帖子

为什么FS#不能从C#中看到FSharpOption的某些属性(例如IsSome和IsNone)?

在我看来,F#选项类型的某些属性在C#项目中是不可见的.通过检查类型,我可以看到或多或少的原因,但我真的不明白究竟发生了什么,为什么做出这些选择或如何最好地规避问题.

这里有一些片段展示了这个问题.我有一个包含两个项目的VS2015解决方案,一个C#项目和一个F#项目.在F#项目中,我有一个类定义如下:

type Foo () =

    member this.Bar () = Some(1)
Run Code Online (Sandbox Code Playgroud)

此外,在F#中,我可以这样写:

let option = (new Foo()).Bar()
let result = if option.IsNone then "Is none" else "Is some"
Run Code Online (Sandbox Code Playgroud)

所以看起来选项类型有一个名为的属性IsNone.现在,在C#项目中,我引用了从F#项目编译的.dll.这允许我写例如

var optionType = new Foo().Bar();
Run Code Online (Sandbox Code Playgroud)

变量optionType是一个FSharpOption<int>.如上所述,当我在F#项目中使用选项类型时,我通常可以访问例如IsSomeIsNone属性.但是,当我尝试写类似的东西时optionType.IsNone,我得到CS1546错误"属性,索引器或事件......语言不支持".与此一致,Intellisense没有检测到属性:

Intellisense不会检测IsSome和IsNone属性

现在,在检查FSharpOption类型时,我可以看到IsNone和IsSome"属性"显示为静态方法:

来自C#的FSharpOption类签名

另一方面,当我从F#检查类型时,我看到以下内容:

来自F#的FSharpOption类签名

在这里,属性的"存在" IsSome,并IsNone可见一斑.将光标悬停在这些属性上,VS2015给出了以下注释:"包含类型可以使用'null'作为其nullary union case的表示值.该成员将被编译为静态成员." 这就是除了静态方法(如lukegv和Fyodor Soikin所述)之外,这些属性不可用的原因.

因此,情况似乎如下:编译的FSharpOption类型没有任何IsNone和IsSome属性.F#中的幕后工作正在进行,以启用模拟这些属性的功能.

我知道我可以通过使用OptionModuleMicrosoft.FSharp.Core 来解决这个问题.但是,似乎这个功能是F#核心库的架构师有意识的选择.选择的原因是什么?并且正在使用OptionModule正确的解决方案,还是有更好的方法来使用FSharpOption<T>C#中的类型?

c# f# interop properties

11
推荐指数
1
解决办法
615
查看次数

在组合泛型和非泛型类时,键入变量转义范围

我在F#中有一个带有单个类型参数的泛型类,并且想要创建一个包含工厂方法的静态类.当我编写类时,F#编译器会生成与"转换其范围的类型变量"相关的错误.我的问题是为什么错误存在以及如何解决它.

我创建了一个最小尺寸代码段来演示此问题:

type Foo<'a>(element : 'a) =

    member this.Copy () = Bar.Create(element)

and Bar =

    static member Create(element : 'a) = new Foo<'a>(element)
Run Code Online (Sandbox Code Playgroud)

类型中的相互递归是因为我希望类型Foo<'a>能够在静态类中调用工厂方法.上面的代码片段没有编译,错误是:"类型推断导致类型变量a逃避其范围.考虑添加显式类型参数声明或调整代码以减少通用." 错误被注册为位于类的Create方法中Bar.不幸的是,我并不是真的了解这个问题,也不知道如何解决它.有任何想法吗?

这是另外一个观察.片段

type Foo<'a>(element : 'a) =

    member this.Element = element

and Bar =

    static member Create(element : 'a) = new Foo<'a>(element)
Run Code Online (Sandbox Code Playgroud)

编译.所以问题似乎与基于类Copy()方法的类型推断有关Foo<'a>.此外,该片段

type Foo<'a>(element : 'a) =

    member this.Copy () = Bar.Create(element)

and Bar =

    static member Create<'a>(element) = new Foo<'a>(element)
Run Code Online (Sandbox Code Playgroud)

是一个更像C#的代码版本(其中静态方法明确地是通用的),它也没有编译,错误"这段代码不够通用.类型变量'a不能一概而论,因为它会逃避其范围."

generics f# static-methods types type-inference

6
推荐指数
1
解决办法
275
查看次数

在F#接口中实现GetSlice切片

F#支持"切片表达式",例如对于传统的一维数组,其myArray允许诸如的表达式myArray.[3 .. 5].根据例如F#4.0语言规范(第6.4.7节),这是通过在适当转换参数后调用GetSlice方法来实现的.这也适用于多维数组.但是,我在定义在二维情况下实现它的接口时遇到了一些麻烦.

我所做的是以下内容.我已经定义了一个接口如下:

type IMatrix =

    abstract member GetSlice : ?start1:int * ?end1:int * ?start2:int * ?end2:int -> IMatrix
    abstract member GetSlice : idx1:int * ?end1:int * ?start2:int * ?end2:int -> IMatrix
    abstract member GetSlice : ?start1:int * ?end1:int * idx2:int -> IMatrix
Run Code Online (Sandbox Code Playgroud)

这基于我从说明书第6.4.7节中理解的说明.我的想法是,当我有一个IMatrix名字时matrix,我应该能够写作

matrix.[1 .. 2, 3 .. 4]
Run Code Online (Sandbox Code Playgroud)

并得到一个类型的子矩阵IMatrix.这个想法本质上是由编译器1 .. 2转换Some 1, Some 23 .. 4转换为Some 3, Some 4,并且这四种选项类型都给出了四参数 …

arrays f# functional-programming interface multidimensional-array

5
推荐指数
1
解决办法
106
查看次数

如何使用重载的静态运算符

我在F#中编写了一个很小的矩阵库(主要是包装器方法),并且有一个关于静态运算符方法重载的问题,F#选择了一个我不打算过载的重载.

我有一个模块,我已经定义了矩阵与向量的右乘法:

[<AutoOpen>]
module MatrixOps =

let (*) (matrix : IMatrix) (vector : IVector) =
    (...)
Run Code Online (Sandbox Code Playgroud)

这让我可以编写像A*v这样的东西,其中A是IMatrix而v是IVector.但是,我现在在上面的let-binding下面添加以下行:

let z = 1.0 * 2.0
Run Code Online (Sandbox Code Playgroud)

然后,F#编译器将此识别为错误.将鼠标悬停在"1.0"上,我得到:"类型'浮点'与'IMatrix'类型不兼容,同样,悬停在"2.0"上,我得到:"类型'浮点'与类型不兼容' IVector'".这里发生的事情似乎是F#编译器无法对浮点数应用乘法运算符,而是将运算符应用于IMatrix和IVector.如果我反而写

let z = (1.0 : float) * (2.0 : float)
Run Code Online (Sandbox Code Playgroud)

问题仍然存在,因此添加显式类型注释并没有帮助.如何确保F#选择浮动乘法运算符而不是上面定义的IMatrix/IVector运算符?

f# static-methods type-inference operator-overloading

4
推荐指数
1
解决办法
138
查看次数

为什么F#中的这个接口实现不能编译?

我正在尝试为IEquatable<T>F#中的特定类实现.但是,在这个特定的情况下这样做时,我会收到意外错误.

我有以下代码:

type Foo private (name : string) = 

member this.Name = name

member this.Equals (other : Foo) = this.Name = other.Name

override this.Equals other =
    match other with | :? Foo as foo -> this.Equals foo | _ -> false

override this.GetHashCode () = this.Name.GetHashCode ()

interface IEquatable<Foo> with
    this.Equals other = this.Equals other
Run Code Online (Sandbox Code Playgroud)

这不编译.我收到以下错误:"带有'成员定义'的意外关键字'.另外,我收到了"可能不正确的缩进..."警告.我不知道问题是什么,因为在我看来,上面接口通常是如何在F#中实现的.为什么上面没有编译?

generics f# equality interface

3
推荐指数
1
解决办法
122
查看次数

访问F#中的GetSlice方法

我正在为F#中的矩阵类实现切片表达式,这意味着我必须实现三种GetSlice方法.我的问题是通过利用核心库中的现有功能来获得有效的方法.这三种方法的签名如下:

member GetSlice : idx1:int * start2:int option * end2:int option -> IMatrix
member GetSlice : start1:int option * end1:int option * idx2:int -> IMatrix
member GetSlice : start1:int option * end1:int option * 
                  start2:int option * end2:int option -> IMatrix
Run Code Online (Sandbox Code Playgroud)

考虑这三个中的最后一个.矩阵类有一个私有float[,]字段entries,用于保存矩阵数据.最自然的实现是这样的:

member this.GetSlice (?start1 : int, ?end1 : int, ?start2 : int, ?end2 : int) =
    let newEntries = entries.GetSlice(?start1 = start1, ?end1 = end1,
                                      ?start2 = start2, ?end2 = end2)
    new Matrix(newEntries), …
Run Code Online (Sandbox Code Playgroud)

arrays f# functional-programming pattern-matching multidimensional-array

2
推荐指数
1
解决办法
257
查看次数