2011-09-19 21 views
13

add neden sub neden bir istisna atar bilen var mı? Ve bu bir böcek mi?'Satır içi' ve tırnak değerlendirmesini kullanırken (+) ve (-) arasındaki tutarsız davranış

open Microsoft.FSharp.Linq.QuotationEvaluation 

let inline add x = x + x 
let inline sub x = x - x 

let answer = <@ add 1 @>.Eval() // 2, as expected 
let answer2 = <@ sub 1 @>.Eval() // NotSupportedException 

Not satır içi anahtar sözcüğü olmadan özel durum değildir (ancak kod jenerik değildir) alıntılar kullanırken Ayrıca istisna sadece atılır. Normal değerlendirme iyi çalışıyor.

Teşekkür

Düzenleme: Bu soru için basitleştirilmiş kod örneği

+0

PowerPack en kullanmamaya çalışın değerlendirme yöntemleri Eğer gerçekten gerçekten ihtiyacınız varsa, teklifleri değerlendirmenin başka yolları da var: Örneğin, Stephen Swensen'in Unquote'u (http://code.google.com/p/unquote/) –

+0

@Ramon - ciro ve Unquote'un değerlendiricisinin bir çok senaryoda daha iyi bir seçenek olabileceğine katılıyorum (daha hızlı derlenmemiş değerlendirme, daha fazla kotasyon kalıplarını destekler, Silverlight 4'ü destekler, daha basit olması sayesinde daha az buggy destekler), işaret etmem gerek Bu sorunun herhangi bir değerlendirme motorunun ele alabileceğinden daha derin olduğunu ve Unquote'un değerlendiricisinde de görülebilir: “NoDynamicInvocation” operatörüne “zahmetsiz çağrı” derleme zamanında gömülür ve etrafta işlenemez. –

+1

Temelde aynı sorun için bir süre önce PowerPack projesinde bir hata yaptım (gerçi bunu anlamasam da - o anda sorun): http: //fsharppowerpack.codeplex.com/workitem/5882, ama şimdi bunun derleyici ekibine doğrudan bildirilmesi gereken bir şey olduğuna inanıyorum. –

cevap

13

Teşekkür - bu basit bir repro ile gerçekten güzel bir hata raporu ve bu inanamadım, ama tamamen haklısın. Artı çalışıyor ama eksi yapmıyor.

sorun jenerik yöntemler ve LINQ versiyonu bu jenerik yöntemler çağırır olarak sub ve add derlenmiş olmasıdır. Satır alıntılar saklandıktan sonra gerçekleştirilir, böylece tırnak içinde kod sub yöntemine çağrı içerir. Bu normal F # kodunda bir sorun değildir, çünkü işlevler satır içi ve işleçler bazı sayısal türlerde + veya - çözülür. Ancak, genel sürüm dinamik bir arama kullanır. Eğer prim-types.fs:3530 içine bakarsanız, görürsünüz:

let inline (+) (x: ^T) (y: ^U) : ^V = 
    AdditionDynamic<(^T),(^U),(^V)> x y 
    when ^T : int32  and ^U : int32  = (# "add" x y : int32 #) 
    when ^T : float  and ^U : float  = (# "add" x y : float #) 
    // ... lots of other cases 

AdditionDynamic jenerik yöntemle çağrılan şeydir. Daha yavaş olacak dinamik arama yapar, ancak işe yarayacaktır. Ben herhangi bir teknik sebebi var olduğunu düşünmüyorum, ama sizi açıklıyor - neden bu durumda hiç bir fikrim yok

[<NoDynamicInvocation>] 
let inline (-) (x: ^T) (y: ^U) : ^V = 
    ((^T or ^U): (static member (-) : ^T * ^U -> ^V) (x,y)) 
    when ^T : int32  and ^U : int32  = (# "sub" x y : int32 #) 
    when ^T : float  and ^U : float  = (# "sub" x y : float #) 
    // ... lots of other cases 

: İlginçtir, eksi operatörü için, F # kütüphane dinamik uygulanmasını içermemektedir rapor ettiğin davranışı al. Derlenmiş kodu ILSpy kullanarak bakarsanız, add yönteminin bir şey yaptığını ve sub yönteminin attığını görürsünüz (bu, istisnanın nereden geldiğini gösterir).

Bir geçici çözüm'a gelince, kodu, jenerik eksi işlecini kullanmadığı bir şekilde yazmanız gerekir. Muhtemelen en iyi seçenek() this post (bkz sub_int veya sub_float kullanarak ya) ya da DLR kullanarak oldukça verimli muhtemelen yapılabilir sub kendi dinamik uygulama (yazarak inline fonksiyonlarını kaçınmaktır.

+0

Neden inline sub x = x + (-x) 'çalışmasına izin vermiyor? Aynı nedenden dolayı, tek bir olumsuzluk için dinamik bir etki yok mu? – Daniel

+0

@Daniel - yep. Etrafa baktıktan sonra (DynamicImplTable'ı, dinamik uygulamayı destekleyen tüm işlemlerin bir listesini almak için arayın), bunu yapmanın bir yolu olduğunu düşünmüyorum. '+', '*', Jenerik, jenerik sıfır, 'sign' ve diğer birkaçını kullanabilirsiniz. Bu :-) –

+2

kullanarak çıkarma yapmak nasıl göremiyorum Unquote için bir tırnak değerlendirme motoru uygulayarak aslında bu sorunu acı olarak biliyorum. Dinamik çağrı desteğine sahip olmayan çok sayıda * çekirdek operatör vardır ve bunlara sahip olanların ve olmayanların seçimlerinde herhangi bir tutarlılık görülmemektedir. Bu, herhangi bir teklif değerlendirme motorunun, eksik olanlar için özel dinamik çözünürlük uygulaması gerektiği anlamına gelir (performans, özellikle sayısal operatörler için olsa da, yine de yapmak için başka bir zorlayıcı sebeptir): http://code.google.com/p/unquote/source/browse/ etiket/2.1.0/Unquote/DynamicOperators.fs –