lensler, fclabels, veri erişimci - yapı erişimi ve mutasyon için hangi kütüphane daha iyidir


173

Kayıt alanlarına erişmek ve işlem yapmak için en az üç popüler kütüphane vardır. Bildiklerim: veri erişimcisi, fclabels ve lensler.

Şahsen veri erişimci ile başladım ve şimdi kullanıyorum. Ancak son zamanlarda haskell-cafe üzerinde fclabels üstün olmak bir görüş vardı.

Bu yüzden bu üç (ve belki daha fazla) kütüphanenin karşılaştırılması ile ilgileniyorum.


3
Bugün itibariyle, lenspaket en zengin işlevsellik ve belgelere sahiptir, bu yüzden karmaşıklığını ve bağımlılıklarını önemsemiyorsanız, bu yoludur.
modüler

Yanıtlar:


200

Lens sağladığımı bildiğim en az 4 kütüphane var.

Bir lens kavramı, izomorfik bir şey sağlamasıdır.

data Lens a b = Lens (a -> b) (b -> a -> a)

iki işlev sağlayan: bir alıcı ve bir ayarlayıcı

get (Lens g _) = g
put (Lens _ s) = s

üç yasaya tabidir:

İlk olarak, bir şey koyarsanız, geri alabilirsiniz

get l (put l b a) = b 

İkincisi, alıp sonra ayar cevabı değiştirmez

put l (get l a) a = a

Ve üçüncüsü, iki kez koymak bir kez koymakla aynıdır, daha doğrusu ikinci koymak kazanır.

put l b1 (put l b2 a) = put l b1 a

Tip sisteminin bu yasaları sizin için kontrol etmek için yeterli olmadığını unutmayın, bu nedenle hangi lens uygulamasını kullanırsanız kullanın, kendiniz sağlamanız gerekir.

Bu kütüphanelerin birçoğu üstte bir sürü ekstra birleştirici sağlar ve genellikle basit kayıt türleri alanları için lensleri otomatik olarak oluşturmak için bir çeşit şablon haskell makinesi sağlar.

Bunu göz önünde bulundurarak, farklı uygulamalara dönebiliriz:

Uygulamalar

fclabels

fclabels belki de objektif kütüphaneleri hakkında en kolay anlaşılan şeydir , çünkü a :-> bdoğrudan yukarıdaki türe çevrilebilir. Lens oluşturmanıza izin verdiği için yararlı olan bir Kategori örneği (:->)sağlar. Ayrıca kanunsuz birPoint burada kullanılan bir lens kavramını genelleştiren tür ve izomorfizmlerle uğraşmak için bazı sıhhi tesisat sağlar.

Benimsenmesinin bir engeli fclabels, ana paketin şablon-haskell tesisatını içermesidir, bu nedenle paket Haskell 98 değildir ve (oldukça tartışmalı olmayan) TypeOperatorsuzantıyı gerektirir.

Veri erişimci

[Düzenle: data-accessorartık bu temsili kullanmıyor, ancak buna benzer bir forma taşındı data-lens. Yine de bu yorumu saklıyorum.]

Veri erişimci göre biraz daha popüler fclabelsçünkü kısmen, bir Haskell 98 Bununla birlikte, iç temsil kendi seçimi bana ağzımda biraz kusmak.

TBir lensi temsil etmek için kullandığı tip dahili olarak

newtype T r a = Cons { decons :: a -> r -> (a, r) }

Sonuç olarak, getbir merceğin değeri için, 'a' argümanı için tanımlanmamış bir değer göndermelisiniz! Bu bana inanılmaz derecede çirkin ve özel bir uygulama olarak dikkat çekiyor.

Bununla birlikte, Henning sizin için erişimcileri otomatik olarak ayrı bir ' veri erişimci şablonu ' paketinde oluşturmak için şablon haskell tesisatını dahil etti .

Halihazırda kullanan, Haskell 98 olan ve çok önemli olan oldukça büyük bir paket setinin avantajına sahiptir. Category çok örneği , bu nedenle sosisin nasıl yapıldığına dikkat etmezseniz, bu paket aslında oldukça makul bir seçimdir. .

lensler

Daha sonra, lensleri doğrudan bu tür monad homomorfizmleri olarak tanımlayarak, bir merceğin iki durum monad arasında bir durum monad homomorfizması sağlayabildiğini gözlemleyen lens paketi vardır .

Gerçekten lensleri için bir tür sağlamak için rahatsız olsaydı, bir rütbe-2 türü olurdu:

newtype Lens s t = Lens (forall a. State t a -> State s a)

Sonuç olarak, bu yaklaşımı sevmiyorum, çünkü Haskell 98'den gereksiz bir şekilde sizi çekiyor (eğer objektiflerinizi soyut olarak sağlamak için bir tür istiyorsanız) ve sizi Categorylens örneğinden mahrum eder , bu da size izin verir onları oluşturmak .. Uygulama ayrıca çok parametreli tip sınıfları gerektirir.

Burada belirtilen diğer tüm lens kütüphaneleri bir birleştirici sağlar veya aynı durum odaklama efektini sağlamak için kullanılabilir, bu nedenle lensinizi doğrudan bu şekilde kodlayarak hiçbir şey kazanılmaz.

Ayrıca, başlangıçta belirtilen yan koşulların bu formda gerçekten hoş bir ifadesi yoktur. 'Fclabels'de olduğu gibi, bu, doğrudan ana pakette bir kayıt türü için lensleri otomatik olarak oluşturmak için şablon haskell yöntemi sağlar.

CategoryÖrneğin, barok kodlama eksikliği ve ana paketteki şablon haskell gereksinimi nedeniyle, bu benim en sevdiğim uygulama.

veri lensli

[Düzenle: 1.8.0'dan itibaren bunlar comonad-transformers paketinden veri lensine taşındı]

Benim data-lenspaketi açısından lensler sağlar Mağaza comonad.

newtype Lens a b = Lens (a -> Store b a)

nerede

data Store b a = Store (b -> a) b

Genişletilmiş bu eşdeğer

newtype Lens a b = Lens (a -> (b, b -> a))

Bunu, öğeyi almanın sonucundan oluşan bir çifti döndürmek için alıcıdan ve ayarlayıcıdan ortak argümanı ve yeni bir değer koymak için bir ayarlayıcıyı çarpan olarak değerlendirebilirsiniz. Bu, 'ayarlayıcı'nın burada değeri elde etmek için kullanılan bazı çalışmaları geri dönüştürebilir fclabels, özellikle tanımlayıcılar zincirlendiğinde tanımdan daha verimli bir 'değiştirme' işlemi sağlar .

Bu temsil için hoş bir teorik gerekçe de vardır, çünkü bu cevabın başlangıcında belirtilen 3 yasayı karşılayan 'Lens' değerlerinin alt kümesi, sarılmış fonksiyonun mağaza komonad için bir 'comonad kömürü' olduğu lenslerdir. . Bu, bir lens için 3 tüylü kanunu l2 güzel puansız eşdeğerine dönüştürür:

extract . l = id
duplicate . l = fmap l . l

Bu yaklaşım ilk olarak belirtildiği ve Russell O'Connor tarif edilmiş Functorolan Lensşekilde Applicativeetmektir Biplate: Tanıtımı multiplate edildi ve bir ön baskı dayalı blogged hakkında Jeremy Gibbons tarafından.

Ayrıca, kesinlikle lenslerle çalışmak için bir dizi birleştirici ve kaplar için bazı stok lensleri içerir Data.Map.

Yani data-lensa Category( lensespaketin aksine ) biçimindeki lensler Haskell 98 ( fclabels/ aksine / lenses), aklı başında (arka ucundan farklı olarak data-accessor) ve biraz daha verimli bir uygulama sağlıyor, data-lens-fddışarıya çıkmak isteyenler için MonadState ile çalışma işlevselliği sağlıyor Haskell 98, ve şablon-haskell makineleri artık mevcut data-lens-template.

28.06.2012 Güncellemesi: Diğer Lens Uygulama Stratejileri

İzomorfizma Lensleri

Dikkate değer diğer iki lens kodlaması vardır. Birincisi, bir lensi bir yapıyı alanın değerine kırmanın bir yolu ve 'diğer her şey' olarak görmenin güzel bir teorik yolunu verir.

İzomorfizm için bir tür verilir

data Iso a b = Iso { hither :: a -> b, yon :: b -> a }

geçerli üyeler tatmin edecek hither . yon = idveyon . hither = id

Aşağıdakileri içeren bir lensi temsil edebiliriz:

data Lens a b = forall c. Lens (Iso a (b,c))

Bunlar öncelikle lenslerin anlamını düşünmenin bir yolu olarak kullanışlıdır ve bunları diğer lensleri açıklamak için bir muhakeme aracı olarak kullanabiliriz.

van Laarhoven Lensler

Objektifleri kullanarak örnek oluşturarak (.)ve örnek idolmadan bile oluşturulacak şekilde modelleyebilirizCategory

type Lens a b = forall f. Functor f => (b -> f b) -> a -> f a

bizim lensler için türü olarak.

Daha sonra bir lens tanımlamak kadar kolaydır:

_2 f (a,b) = (,) a <$> f b

ve fonksiyon kompozisyonunun lens kompozisyonu olduğunu kendiniz de doğrulayabilirsiniz.

Yakın zamanda , bu imzayı genelleştirerek, alan türlerini değiştirebilecek lens ailelerini elde etmek için van Laarhoven lenslerini nasıl daha genelleştirebileceğiniz hakkında yazdım.

type LensFamily a b c d = forall f. Functor f => (c -> f d) -> a -> f b

Bunun, lensler hakkında konuşmanın en iyi yolunun 2. sıra polimorfizmini kullanmak olduğu talihsiz bir sonucu var, ancak lensleri tanımlarken bu imzayı doğrudan kullanmanıza gerek yok.

Lensİçin yukarıda tanımlanan I _2aslında bir olduğunu LensFamily.

_2 :: Functor f => (a -> f b) -> (c,a) -> f (c, b)

Lensleri, lens ailelerini ve alıcılar, ayarlayıcılar, kıvrımlar ve çapraz geçişler gibi diğer genellemeleri içeren bir kütüphane yazdım. Paket olarak hackage'de mevcuttur lens.

Yine, bu yaklaşımın en büyük avantajı, kütüphane Functor f => (b -> f b) -> a -> f asahiplerinin, 'a' ve 'b' türlerine sadece tür işlevler sağlayarak herhangi bir objektif kütüphanesi bağımlılığı yaratmadan kütüphanelerinizde bu tarzda objektifler oluşturabilmeleridir . Bu, benimseme maliyetini büyük ölçüde azaltır.

Yeni lensleri tanımlamak için paketi kullanmanız gerekmediğinden, Haskell 98 kütüphanesini koruma konusundaki önceki endişelerimden çok fazla baskı gerekiyor.


28
Ben iyimser yaklaşım için fclabels seviyorum:->
Tener


10
Haskell 1998 ile uyumlu olmak önemli mi? Derleyici geliştirmeyi kolaylaştırdığı için? Bunun yerine Haskell 2010 hakkında konuşmaya geçmemeliyiz?
yairchu

55
Oh hayır! Orijinal yazarıydım data-accessorve daha sonra Henning'e geçtim ve dikkat etmeyi bıraktım. a -> r -> (a,r)Temsilciliği de beni rahatsız eder, ve benim orijinal uygulama sadece gibiydi Lenstip. Heeennnninngg !!
luqui

5
Yairchu: çoğunlukla kütüphanenizin ghc dışında bir derleyici ile çalışma şansı olabilir. Başka kimse sahip şablon Haskell. 2010 burada alakalı bir şey eklemiyor.
Edward KMETT
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.