2016-05-19 31 views
11

Bir operatörün değişmez olduğunu belirtmenin bir yolu var, bu yüzden her iki yönde de aynı tanımları vermek zorunda kalmam. Örneğin: BuradaHaskell Operatörleri için Değişken Özelliği?

data Nat = Zero | Succ Nat 

(+) :: Nat -> Nat -> Nat 
Zero + x = x 
x + Zero = x 
... 

, bir yol onlardan biri diğerinden ima olacağını, ben bu tanımların her ikisi vermek olmazdı öyle mi var? fn = flip fn'un açıklanmasının bir yolu var mı?

+0

Normal olarak eklemeyi tanımlayabilir ve ücretsiz olarak (yavaş) değişebilirlik elde edebilirsiniz. – ThreeFx

+2

Ayrıca, bu zaten bir yanıt var [burada] (http://stackoverflow.com/questions/29210248/haskell-defining-commutative-functions-how-to-consider-actual-arguments-by-co). (Kullanım durumunuzdan daha geneldir, bu nedenle muhtemelen önerilen paketi nasıl kullanacağınız konusunda biraz araştırma yapmanız gerekir) – ThreeFx

+0

Eğer tembelliği hesaba katarsanız hemen hemen hiçbir işlem tamamen değişkendir, çünkü tipik olarak 'f tanımsız x 'farklı olabilir. fx undefined ', desen eşleştirmesinin aslında ardışık olması nedeniyle. İşlevsel dillerin işlevsel ve anlamsal semantiği arasında tam bir soyutlama elde etmenin bu kadar zor olmasının nedeni budur: anlamsal anlamlarda, aslında dilde tanımlanamayan paralel ya da benzeri işlevleri içerir. – Bakuriu

cevap

9

Bu ekleme operatör için gerekli değildir, ancak genel olarak argümanları çevirir nihai denklemi ekleyerek tüm çevrilmiş davaları uygulamadan bir işlev değişmeli yapabilirsiniz:

data X = A | B | C 

adjacent A B = True 
adjacent B C = True 
adjacent A C = False 
adjacent x y = adjacent y x -- covers B A, C B, and C A 

Ancak, olumsuz olmasıdır Eğer bir durumun ele alınması unutursanız, bu kolayca sonsuz bir döngüye yol açar:

İşte
adjacent A B = True 
adjacent B C = True 
adjacent x y = adjacent y x 

, adjacent A C vb adjacent A C arama ve hangi, adjacent C A çağırır. Ve GHC’nin desen eşleme kontrolü (-fwarn-incomplete-patterns veya -Wall) burada size yardımcı olmaz.

Sana döngü önlemek için ek bir bağımsız değişken sanırım: Eğer çevirdi ama hiçbir maç oldu hala durumun ele alınması go Reverse denklem eklemek yoksa

data Commute = Forward | Reverse 

adjacent = go Forward 
    where 
    go _ A B = True 
    go _ B C = True 
    go Forward x y = go Reverse y x -- try to commute 
    go Reverse _ _ = False   -- commuting failed 

Şimdi GHC şikayet edecektir.

Ancak, bunun yalnızca çok sayıda durumda olan işlevler için uygun olduğunu düşünüyorum. Aksi takdirde, hepsini sıralamak daha nettir.

+1

Mükemmel ve basit, teşekkürler! Bunu neden düşünmediğimi bilmiyorum. –

+1

Ayrıca, GHC, özyinelemeli fonksiyonların (çok fazla durmayacağı için!) Çok dikkatlidir, bu yüzden bu tekniği kullanmak, derleyici optimizasyonlarını engelleyebilir. Tabii ki, GHC'nin gerçekten * değil * özyinelemeli olduğunu ve inline olduğunu anlamasına rağmen, bu kadar akıllı olduğundan emin değilim. – dfeuer

2

cevap olarak söylemek gerekirse: Bu, anlamı her iki yönde etkili olmasa da,

(+) :: UInt -> UInt -> UInt 
Zero + x = x 
(Succ s) + x = s + (Succ x) 

Bu işlem değişmeli geçerli: Düzenli eklenmesini uygulamak Evet, eğer otomatik değişmeli operasyonla sona Bu "big number as UInt" + Zero, Zero + "big number as UInt"'dan daha uzun sürer, çünkü ekleme operatörü bu şekilde tanımlanır.

ghci> :set +s 
ghci> bignum + Zero 
number as uint 
(0.01 secs, 4,729,664 bytes) -- inefficient O(n) operation 
ghci> Zero + bignum 
number as uint 
(0.00 secs, 0 bytes) -- instant constant operation 

Bunu düzeltmenin kolay bir yolu yaptığınız işi ekleme işlemini açık bir şekilde tanımlamaktır.