F# 代码错误还是我的误解?
我看到了无法从F#编译器(Visual F#3.1.1.0)中解释的行为——表面上看起来只是命名局部和传递临时之间的区别,实际上产生了行为差异 我是不是不了解F#行为,还是这是一个代码生成错误?(我知道,后者的可能性更大。) 重新编程-我发现在不使用反应式扩展的情况下很难重新编程,所以这和我得到的一样简单。请注意,F# 代码错误还是我的误解?,f#,F#,我看到了无法从F#编译器(Visual F#3.1.1.0)中解释的行为——表面上看起来只是命名局部和传递临时之间的区别,实际上产生了行为差异 我是不是不了解F#行为,还是这是一个代码生成错误?(我知道,后者的可能性更大。) 重新编程-我发现在不使用反应式扩展的情况下很难重新编程,所以这和我得到的一样简单。请注意,try1和try2几乎相同 open System open System.Reactive.Linq open System.Threading let interval = Ti
try1
和try2
几乎相同
open System
open System.Reactive.Linq
open System.Threading
let interval = TimeSpan.FromSeconds(0.5)
let testDuration = TimeSpan.FromSeconds(2.0)
let mkHandler () = // creates a function that closes over state
let count = ref 0
fun _ -> count := !count + 1
printfn "State is now %d" !count
let try1 () =
printfn "try1"
let handler = mkHandler ()
use subscription = Observable.Interval(interval).Subscribe(handler)
Thread.Sleep(testDuration)
let try2 () =
printfn "try2"
// creates handler inline:
use subscription = Observable.Interval(interval).Subscribe(mkHandler ())
Thread.Sleep(testDuration)
[<EntryPoint>]
let main argv =
try1 ()
try2 ()
0
根据我的理解,try2
的行为应该与try1
相同。如果没有,请解释这一微小差异应如何发挥不同的作用
通过检查反编译器的输出,我确定了以下几点:
mkHandler
功能正常;它创建一个关闭唯一状态的函数。当多次调用时,它会改变该状态
try1
和try2
都调用了相同的Subscribe
重载:公共静态IDisposable Subscribe(此IObservable源,Action onNext)
为try1
生成的幕后助手代码关闭处理程序函数并正确调用它:
[CompilationMapping(SourceConstructFlags.Closure)]
[Serializable]
// subscription@16
internal sealed class subscriptionu004016
{
public FSharpFunc<long, Unit> handler;
public subscriptionu004016(FSharpFunc<long, Unit> handler)
{
}
internal void Invoke(long obj)
{
this.handler.Invoke(obj);
}
}
重申我的问题:为什么这两个函数的行为不同?这是代码生成错误吗?以上都没有?据我所知,您的代码没有任何问题-您所做的一切都是有意义的。这似乎是F#编译器中的一个微妙缺陷 我怀疑编译器解析
Subscribe
方法的方式有问题。您的代码正在创建一个F#函数值,但编译器会自动将其包装到Action
委托中,并使用Subscribe
的Rx版本。但是,它通常不会自动将部分应用的函数转换为委托-似乎只有在这种情况下才会发生
最简单的解决方法似乎是更改mkHandler
函数以显式创建委托,然后一切按预期工作:
let mkHandler () = // creates a function that closes over state
let count = ref 0
Action<int64>(fun _ ->
count := !count + 1
printfn "State is now %d" !count)
然后完全按照你所做的去做:
let partial() =
printfn "called"
fun n -> ()
let a = new Event<int>()
let o = a.Publish.Subscribe(partial())
let partial()=
printfn“调用”
乐趣n->()
设a=新事件()
让o=a.Publish.Subscribe(partial())
这个打印两次“调用”,而实际上应该只调用一次。我创建了一个.我有另一个仅使用F#的复制,没有RX或可观测值:嗯,因此转换到
操作
委托似乎真的有问题。您能否将此示例添加到CodePlex问题中?()
let mkHandler () = // creates a function that closes over state
let count = ref 0
Action<int64>(fun _ ->
count := !count + 1
printfn "State is now %d" !count)
public static class Extensions {
public static void Subscribe(this IObservable<int> c1, Action<int> f) {
f(1);
f(2);
}
}
let partial() =
printfn "called"
fun n -> ()
let a = new Event<int>()
let o = a.Publish.Subscribe(partial())