这个问题始于
SML.NET可以做仿函数并使用Microsoft .NET.
*请参阅:SML.NET用户指南第4.8.2节类类型和仿函数?
由于Microsoft .NET的一些限制,我一直看到F#无法做真正的仿函数.
*ML仿函数可以用.NET完全编码(C#/ F#)吗?
*算子的任何解决方法?
那么如果SML.NET可以在.NET上运行仿函数那么为什么F#不能呢?SML.NET做了什么,F#不能做什么?
我越了解来自类别理论的仿函数,我越看到它们的美丽,并希望在F#中拥有它们.
编辑
通常在F#中编写通用代码时,我会遇到与此类似的情况(我知道这非常低效,仅用于演示目的):
let isPrime n =
let sq = n |> float |> sqrt |> int
{2..sq} |> Seq.forall (fun d -> n % d <> 0)
Run Code Online (Sandbox Code Playgroud)
对于许多问题,我可以使用静态解析的类型,并通过内联获得性能提升.
let inline isPrime (n:^a) =
let two = LanguagePrimitives.GenericOne + LanguagePrimitives.GenericOne
let sq = n |> float |> sqrt |> int
{two..sq} |> Seq.forall (fun d -> n % d <> LanguagePrimitives.GenericZero)
Run Code Online (Sandbox Code Playgroud)
由于上限序列是一个浮点数,上面的代码将无法编译.非理性地说,我可以退回到int例如.
但是编译器不允许我使用以下任何一个:
let sq = n |> float |> sqrt :> ^alet sq = …我希望能够使用静态方法从其他库扩展类型以启用泛型算法.以VectorN微软新推出的SIMD友好型固定尺寸类型为例.他们定义Zero,他们定义(+),他们定义(/),但我不能使用Array.average它们,因为他们没有定义DivideByInt,我很乐意:
open System.Numerics
type Vector2f with
static member DivideByInt (v:Vector2f) (i:int) = v / Vector2f(single i, single i)
let bigArray : Vector2f[] = readABigFile()
printf "the average is %A" (Array.average bigArray)
Run Code Online (Sandbox Code Playgroud)
但它不会让我编译,抱怨
error FS0001: The type 'Vector2f' does not support the operator 'DivideByInt'
Run Code Online (Sandbox Code Playgroud)
为什么F#编译器中存在此限制?
(编辑:基本上问过同样的问题.)
我试图重置一个Measure类型的(*)运算符.
我想看到的是:
> let x = 1.0<i> * 1.0<i>;;
val x : float = -1.0
Run Code Online (Sandbox Code Playgroud)
以下定义似乎可以解决问题:
> let inline (*) (v1 : float<i>) (v2 : float<i>) = float(-1) * float(v1) * float(v2);;
val inline ( * ) : float<i> -> float<i> -> float
Run Code Online (Sandbox Code Playgroud)
请注意,此示例中的乘积度量正确地解析为<1>,例如在乘以复数的虚数单位时.如果没有此重载定义,则默认产品将解析为<i ^ 2>.
但上面的重载定义有令人讨厌的副作用:
> let y = 1.0 * 1.0;;
let y = 1.0 * 1.0;;
--------^^^
stdin(11,9): error FS0001: This expression was expected to have type
float<i>
but here has type
float
Run Code Online (Sandbox Code Playgroud)
显然,我的重载定义隐藏了浮点类型的(*)运算符.
我究竟做错了什么?
我想了解这个答案的代码
type Mult = Mult with
static member inline ($) (Mult, v1: 'a list) = fun (v2: 'b list) ->
v1 |> List.collect (fun x -> v2 |> List.map (fun y -> (x, y))) : list<'a * 'b>
static member inline ($) (Mult, v1:'a ) = fun (v2:'a) -> v1 * v2 :'a
let inline (*) v1 v2 = (Mult $ v1) v2
Run Code Online (Sandbox Code Playgroud)
F#可以解决重载成员.(因为它不支持成员的currying).所以,我认为,它也适用于方法
但它没有:
type Mult = Mult with
static member inline Do (Mult, v1: 'a list) …Run Code Online (Sandbox Code Playgroud) 让我们说,由于一些奇怪的原因,我希望有这个功能:
let (~-) (str:string) = 42
Run Code Online (Sandbox Code Playgroud)
所以我可以做这样的事情,得到42结果:
-"test"
val it : int = 42
Run Code Online (Sandbox Code Playgroud)
哪个好.但现在我这样做:
let a = 100
-a
Run Code Online (Sandbox Code Playgroud)
我明白了:
error FS0001: This expression was expected to have type
string
but here has type
int
Run Code Online (Sandbox Code Playgroud)
知道为什么会这样吗?