7

Haskell'de Scrap Boilerplate ve jenerik programlama hakkında konuşan insanlar görüyorum. bu terimler ne anlama geliyor? Ne zaman senin Boilerplate Hurda kullanmak istiyorum ve nasıl kullanabilirim? karmaşık veri türlerini dönüşümleri yaparken"Boilerplate'inizi" nedir?

+1

Google'ın bu konuyla ilgili bir sürü dökümanları var. –

+3

@JustinPihony Soruyu sordum çünkü Stack Overflow'un amaçlarından biri, * tüm * programlama sorularına [Googled olanlar bile] yanıt vermektir. (http://meta.stackexchange.com/questions/5280/embrace-the-non-googlers). Bu soru, görebildiğim kadarıyla, daha önce SO üzerinde hiç sorulmamıştı ve bunun, bazı yüksek kaliteli cevaplar üreteceğine inanıyorum. –

+0

Kağıdın 2. Bölümü [Kalibrasyonunuzu hazırlayın - Genel Programlama için Pratik Tasarım Kalıbı] (http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=0088DE3D75D657BE9F2B9E5D705232B3?doi=10.1.1.1.3176&rep=rep1&type= pdf) iyi motive edici bir örnek içerir. – ErikR

cevap

7

Genellikle, sadece başka bir deyişle, yalnız, belirli indirgenebilir ifadeleri, redexes hedefliyorsanız --- yapının küçük parçaları etkileyecek gerekir.

klasik bir örnek tamsayı ifadeler bir tür üzerinde çift olumsuzluk ortadan kaldırılması geçerli:

data Exp = Plus Exp Exp | Mult Exp Exp | Negate Exp | Pure Int 

doubleNegSimpl :: Exp -> Exp 
doubleNegSimpl (Negate (Negate e)) = e 
... 

bile bu örneği açıklarken, ben ... kısmının tamamını dışarı yazmak için yapmamayı tercih ediyorum. Tamamen mekaniktir --- Exp'un tamamında yinelemeye devam etmek için motordan başka bir şey yoktur.

Bu "motor"

biz hurda niyetinde demirbaş olduğunu.


Bunu başarmak için, Kişisel Demirbaş biz veri türleri üzerinde "jenerik traversals" inşa edebileceği bir mekanizma önerir Hurda. Bu geçişler, söz konusu belirli veri türü hakkında hiçbir şey bilmeden tam olarak doğru şekilde çalışır. Bunu yapmak için, çok kabaca, genel açıklamalı ağaçlar kavramımız var.

section :: Generic a => a -> AnnotatedTree 

ve "geçerli" açıklamalı ağaçlar

retract :: Generic a => AnnotatedTree -> Maybe a 
ADT

bazı marka haline geri yansıtılabilir: Bunların hepsi ADTS açıklamalı ağaçların türü içine yansıtılabilir şekilde ADTS daha büyüktür

Özellikle, section ve retract tanımlanmış olan türleri belirtmek için Generic tip yazımını tanıtıyorum. tüm veri tiplerinin bu jenerik, açıklamalı ağaç gösterimini kullanarak

, bir kez ve herkes için bir geçişi tanımlayabilirsiniz. Özellikle, son kullanıcıların hiçbir zaman AnnotatedTree tipine maruz kalmaması için bir arabirim ( section ve retract kullanarak) sağlarız. son ve başlangıç ​​ section ve retract s ile birleştirilir ve bizim açıklamalı ağaçlar hep "geçerli" olduğunu değişmez

everywhere' :: Generic a => (a -> a) -> (AnnotatedTree -> AnnotatedTree) 

böyle, yani biz

everywhere :: Generic a => (a -> a) -> (a -> a) 
everywhere f a0 = fromJust . retract . everywhere' f . section 

vardır: Bunun yerine, biraz benziyor

everywhere f a ne yapar? ADT a'da f "her yerde" işlevini uygulamayı dener. Başka bir deyişle

doubleNegSimpl :: Exp -> Exp 
doubleNegSimpl (Negate (Negate e)) = e 
doubleNegSimpl e     = e 

şöyle Başka bir deyişle, şimdi, bizim çifte olumsuzluk basitleştirilmesi yazma REDEX (Negate (Negate _)) eşleştirememişse yazmasa bile id gibi davranır. Bu

simplify :: Exp -> Exp 
simplify = everywhere doubleNegSimpl 

sonra ikili inkarın için everywhere uygularsanız genel geçişi yoluyla "her yerde" ortadan kalkacaktır.... boilerplate gitti.

+0

denemeye çalıştığı sorunu tanımlamayı ihmal ediyor gibi görünüyor. Her yer bir desenin başarılı bir şekilde eşleşip eşleşmediğini nasıl anlıyor? Genellikle, ayrıntılı olmayan desenler 'IO' da yakalanması gereken bir istisna atar. –

+0

Yapmıyor. "doubleNegSimpl", redex eşleşmediğinde özdeştir, bu yüzden, "her yer", kelimenin tam anlamıyla, her yerde * uygular * ve sadece çoğu yerde bir no-op'tur. Elbette, 'her yer' bunu verimli bir şekilde yapmaya özen gösterir. –

+0

Elbette. Açıkçası dikkatlice okumadım;) –