2017-10-03 19 views
8

Aşağıdaki Haskell kodunu göz önünde bulundurun.Desen eşlemeli işlevleri puntasız biçimde yazmak mümkün mü?

data Keypress = Keypress Int Char 

getSeq :: Keypress -> [Char] 
getSeq (Keypress i c) = replicate i c 

pointfree şeklinde getSeq yazmak için herhangi bir yolu var mı?

getSeq 'ın tanımı o i ve c parametreleri belirterek önlemek için Currying veya monads falan kullanmak için bazı yolu olabilir görünüyor ki onun desen maç için çok benzer. Ancak, pointfree.io, getSeq için noktadan arındırılmış bir çıktı çözümlemiyor, desen eşleştirmesi nedeniyle düşünüyorum.

Mümkün mü?

cevap

16

dönüştürülebilir Özellikle birden kurucular ile özyinelemeli veri türleri için, çoğu zaman yararlıdır olası bir yapıcının her biri için bir fonksiyon verildiğinde bir veri yapısını katlamanın bir yolu olan bir katamorfizmasını tanımlamak için. Örneğin

, Bool için catamorphism

bool :: a -> a -> Bool -> a 
bool x _ False = x 
bool _ y True = y 

ve Either için

either :: (a -> c) -> (b -> c) -> Either a b -> c 
either f g (Left x) = f x 
either f g (Right x) = g x 

Daha gelişmiş catamorphism muhtemelen daha önce gördük listeler için biridir geçerli: foldr!

foldr :: (a -> b -> b) -> b -> [a] -> b 
foldr f init [] = init 
foldr f init (x:xs) = f x (foldr f init xs) 
Biz genellikle (ya da en azından ben değil) Şöyle sanmıyorum

ama foldr bir catamorphism şudur: senin sürece, yinelemeli sizin için liste yapısökümünden desen eşleştirme kolları ve [a] iki yapıcıları bulunan değerler için "işleyicileri" sağlar: (x:xs) işlemek için tip b

  • bir olgu sadece bir değer:

    • bir olgu hiçbir argüman hiç gerek, [] işlemek için. Bu durum, listenin başı olan x'u temsil eden bir argümanı ve ardışık olarak kuyruğu katlama sonucunu temsil eden bir argümanı, b türünde bir değeri alır.

    bir catamorphism tek kurucu ile türü için daha az heyecan verici, ama biz kolayca Keypress türü için bir tane tanımlayabilirsiniz: Bir bakıma

    key :: (Int -> Char -> a) -> Keypress -> a 
    key f (Keypress x c) = f x c 
    

    , catamorphism desen uzakta soyut yapmanızı sağlar -İşlev tanımının eşleme kısmı, daha sonra sadece temel veri türüne artık doğrudan dokunmanıza gerek olmayan işlevlerle çalışabilirsiniz.

    Genel olarak kullanışlı işlevi bir kez tanımladıktan sonra, kalbinizin istediği noktadan bağımsız işlevi uygulamak için bunu birçok kez kullanabilirsiniz. Durumunuzda,

    getSeq :: Keypress -> [Char] 
    getSeq = key replicate 
    
  • 5

    Bir parça boiler olmadan bunu yapamazsınız, ancak lens bu tip bir kazanı sizin için üretebilir, bu nedenle muhtemelen alacağınız kadar yakındır. Esas itibariyle de, bir Iso, tek kurucu veri türü bir birinci sınıf kalıp maça üretecektir Control.Lens.TH den makePrisms kullanarak

    . Uygun olarak, Iso s çift yönlüdür, böylece view onları (desen eşleme gibi değerleri almak için) ve review onları (normalde yapıcıyı kullanmak gibi bir değer koymak için) kullanabilirsiniz.

    makePrisms ve view kullanarak, bir pointfree şekilde getSeq yazmak mümkün:

    {-# LANGUAGE TemplateHaskell #-} 
    import Control.Lens 
    
    data Keypress = Keypress Int Char 
    makePrisms ''Keypress 
    
    getSeq :: Keypress -> [Char] 
    getSeq = uncurry replicate . view _Keypress 
    

    bu mu daha iyi? Fikrim yok. Kodunuzdaki desen eşleşmesi bana iyi görünüyor, ancak zaten zaten lens kullanıyorsanız, bu sürüm sizin için daha uygun olabilir.

    12

    Yazılı olarak, no. Ama isterseniz onu düzeltirim: Sonra

    data Keypress = Keypress 
        { count :: Int 
        , char :: Char } 
    

    getSeq p = replicate (count p) (char p) 
    

    ve bu

    getSeq = replicate <$> count <*> char 
    
    İlgili konular