Sabit uzunluktaki bir listeyi toplam ve zarif bir şekilde nasıl kullanabilirim?


10

Şu anda böyle bir fonksiyonla uğraşıyorum:

foo = (\(a:b:c:d:e:f:_) -> foobar a b c d e f) . (++ repeat def)

Başka bir deyişle, bir liste verildiğinde, bir şey için ilk altı öğeyi kullanır ve liste altı öğeden daha kısasa def, eksik olanlar için bir stand-in olarak kullanır . Bu toplam, ama parçaları (tıpkı gibi map fromJust . filter isJust) değil, bu yüzden sevmiyorum. Herhangi bir kısmi kullanmak gerekmez, bu yeniden yazmaya çalıştım ve var:

foo [] = foobar def def def def def def
foo [a] = foobar a def def def def def
foo [a,b] = foobar a b def def def def
foo [a,b,c] = foobar a b c def def def
foo [a,b,c,d] = foobar a b c d def def
foo [a,b,c,d,e] = foobar a b c d e def
foo (a:b:c:d:e:f:_) = foobar a b c d e f

Teknik olarak istediğimi yaptım, ama şimdi bu devasa bir karmaşa. Bunu nasıl daha zarif ve daha az tekrarlayıcı bir şekilde yapabilirim?


2
Belki, uncons :: Default a => [a] -> (a,[a])varsayılan olarak bir tane yazın def. Ya da bir temerrüt takeWithDef. Ve / veya bir görünüm modeli / kalıp eşanlamı. Bununla birlikte, bazı yardımcı yardımcı kodları yazmayı gerektirir.
chi

@chi Sanırım bununla birlikte gideceğim. Eğer cevap verirsen, kabul edeceğim.
Joseph Sible-Reinstate Monica

2
Değer için, bence bütünlük argümanı case xs ++ repeat def of a:b:c:d:e:f:_ -> ..., sadece iki kez kullanmak ve mevcut cevapların getirdiği tüm ekstra makineleri atlamak hakkında düşünmeyeceğim kadar yerel. Genellikle beni daha çok sinirlendiren (örneğin, birden fazla işlev çağrısında tutulan değişmezleri içeren) daha küresel bütünlük argümanlarıdır.
Daniel Wagner

Aslında takeWithDefnormal bir liste döndürürse kullanılamaz, çünkü bunu eşleştirmemiz gerekir: - / Uygun çözüm Daniel'in ikinci cevabında aşağıda yazdığı şeydir. unconssadece ilk elementi alır, bu yüzden o kadar kullanışlı değil.
chi

Yanıtlar:


8

Güvenli paketi kullanarak şunları yazabilirsiniz:

(!) = atDef def
foo xs = foobar (xs ! 0) (xs ! 1) (xs ! 2) (xs ! 3) (xs ! 4) (xs ! 5)

6

Bu en azından daha kısadır:

foo (a:b:c:d:e:f:_) = foobar a b c d e f
foo xs = foo (xs ++ repeat def)

Desenlerin kapsamlı olduğunu kolayca görebilirsiniz, ancak şimdi her zaman sona erdiğini görmek için biraz düşünmelisiniz. Yani bunu bir gelişme olarak kabul edip edemeyeceğinizi bilmiyorum.

Aksi takdirde, biraz ağır olmasına rağmen devlet monad ile yapabiliriz:

foo = evalState (foobar <$> pop <*> pop <*> pop <*> pop <*> pop <*> pop)
  where
    pop = do xs <- get
             case xs of [] -> pure def
                        y:ys -> put ys >> pure y

Ayrıca sonsuz bir akış türü kullanmayı hayal edebiliyordum.

data S a = S a (S a)

o zaman inşa çünkü foodışarı repeat :: a -> S a, prepend :: [a] -> S a -> S ave take6 :: S a -> (a,a,a,a,a,a), bunların hepsi toplam olabilir. Eğer zaten böyle kullanışlı bir tip yoksa muhtemelen buna değer değil.


3
Akış fikrini çok seviyorum. Gibi bir infix yapıcı ile data S a = a :- S a; infixr 5 :-oldukça temiz görünüyor; foo xs = case prepend xs (repeat def) of a:-b:-c:-d:-e:-f:-_ -> foobar a b c d e f.
Daniel Wagner

4

Sadece eğlence için (ve önerilmez, bu eğlenceler için), işte başka bir yol:

import Data.Default

data Cons f a = a :- f a
infixr 5 :-

data Nil a = Nil -- or use Proxy

class TakeDef f where takeDef :: Default a => [a] -> f a
instance TakeDef Nil where takeDef _ = Nil
instance TakeDef f => TakeDef (Cons f) where
    takeDef (x:xs) = x :- takeDef xs
    takeDef xs = def :- takeDef xs

foo xs = case takeDef xs of
    a:-b:-c:-d:-e:-f:-Nil -> foobar a b c d e f

Desen eşleşmesinde kullandığınız tür, takeDefkaç öğeye bakılacağını söylemek için doğal bir tür düzeyine geçmeye eşittir .


1
Şimdiye kadar tercih ettiğim yaklaşım bu. Muhtemelen tamamlamak için bir görünüm deseni kullanırdım. (Neden "önerilmez"? Eksileri nelerdir?)
Chi

3
Tip düzeyinde programlamaya büyük yatırım yaptığınızda tam olarak neyin yanlış başladığını somutlaştırır: tek satırlık, anında anlaşılabilir bir program olan şey, okuyucunun zihinsel tip çıkarım motorunu ciddi bir şekilde meşgul etmesini gerektiren on hatta ayrılır.
Daniel Wagner

1
Senin değinmek istediğin noktayı anlıyorum. foo (takeDef -> a:-b:-c:-d:-e:-f:-Nil) -> foobar a b c d e fBir satır olarak sayıyorum . Yeniden kullanım için bazı kütüphanede olması gereken kod olduğu için geri kalanını saymıyorum. Sadece bu dava için yazılması gerekiyorsa, söylediğiniz gibi açıkça abartılıyor.
chi
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.