2012-11-26 29 views
15

Bu iki parçacığın neden sözde "yoksul adamın sıkılık analizi" altında farklı sonuçlar ürettiğini anlamak için uğraşıyorum.Veri ve yeni tip arasındaki boşluk/sıkılık

ilk örneği data (doğru bir Uygulamalı örnek varsayılarak) kullanır:

data Parser t a = Parser { 
     getParser :: [t] -> Maybe ([t], a) 
    } 

> getParser (pure (,) <*> literal ';' <*> undefined) "abc" 
*** Exception: Prelude.undefined 

ikinci newtype kullanır. Başka bir fark yoktur:

newtype Parser t a = Parser { 
     getParser :: [t] -> Maybe ([t], a) 
    } 

> getParser (pure (,) <*> literal ';' <*> undefined) "abc" 
Nothing 

literal x onun argümanı ilk belirteci eşleşirse girişinin bir belirteci tüketen başarır bir ayrıştırıcısıdır. Yani bu örnekte, ; bu yana a eşleşmiyor. Ancak, data örnek hala sonraki ayrıştırıcının tanımsız olduğunu görür, newtype örnek yapmaz.

this, this ve this'u okudum, ancak ilk örneklerin neden tanımlanmadığını anlamak için onları yeterince iyi anlamıyorum. Bana öyle geliyor ki, bu örnekte, newtype, data numaralı telefondan daha tembeldir, cevapların tam tersi. (En az one other person da bununla karıştırılmıştır).

data'dan newtype'a geçiş neden bu örneğin tanımını değiştiriyor?


Burada keşfedilen bir şey Bu Uygulamalı örneğiyle, çıkışlar üzerinde data ayrıştırıcı tanımlanmamış: Bu örnek ile, data ayrıştırıcı üzerinde, buna karşın

instance Applicative (Parser s) where 
    Parser f <*> Parser x = Parser h 
    where 
     h xs = 
     f xs >>= \(ys, f') -> 
     x ys >>= \(zs, x') -> 
     Just (zs, f' x') 

    pure a = Parser (\xs -> Just (xs, a)) 

tanımsız olup çıkışı (varsayarak (için doğru bir Monad örneği):

instance Applicative (Parser s) where 
    f <*> x = 
     f >>= \f' -> 
     x >>= \x' -> 
     pure (f' x') 

    pure = pure a = Parser (\xs -> Just (xs, a)) 

Tam kod parçacığı:

import Control.Applicative 
import Control.Monad (liftM) 

data Parser t a = Parser { 
     getParser :: [t] -> Maybe ([t], a) 
    } 


instance Functor (Parser s) where 
    fmap = liftM 

instance Applicative (Parser s) where 
    Parser f <*> Parser x = Parser h 
    where 
     h xs = f xs >>= \(ys, f') -> 
     x ys >>= \(zs, x') -> 
     Just (zs, f' x') 

    pure = return 


instance Monad (Parser s) where 
    Parser m >>= f = Parser h 
    where 
     h xs = 
      m xs >>= \(ys,y) -> 
      getParser (f y) ys 

    return a = Parser (\xs -> Just (xs, a)) 


literal :: Eq t => t -> Parser t t 
literal x = Parser f 
    where 
    f (y:ys) 
     | x == y = Just (ys, x) 
     | otherwise = Nothing 
    f [] = Nothing 
+2

Böyle bir soru sorulduğunda, tüm ilgili kodları eklediğinizde, eğer sığacak kadar küçükse (bu "Functor" ve "Monad" örneklerini ve "literal" içerir), böylece insanlar Fonksiyonları tam olarak nasıl yazdığınızı tahmin etmelisiniz (belirttiğiniz gibi, küçük değişiklikler bile davranışlarda fark yaratabilir). – shachaf

+1

@shachaf asıl soru burada "kodumu nasıl düzeltirim?" - Bunu zaten yaptım - ama “veri” ile “yeni tip” arasındaki farklılık, katılık/tembellik açısından farklı mı? ” Maalesef bu sorudan belli değil. –

+0

Evet, ama yine de, kodun neye benzediğini bilmeden kodunuzda neler olduğunu nasıl açıklayabiliriz? – shachaf

cevap

18

Bildiğiniz gibi, data ve newtype arasındaki temel fark newtype sıkı iken datadata kurucular tembel olmasıdır ile, yani aşağıdaki türde

verilen olmasıdır
data D a = D a 
newtype N a = N a 

D ⊥ `seq` x = x, ancak N ⊥ `seq` x = ⊥.

belki daha az yaygın bilinen Ne Ancak olduğunu bu yapıcıları üzerinde size desen maç, rolleri

constD x (D y) = x 
constN x (N y) = x 
sonra

constD x ⊥ = ⊥ ancak constN x ⊥ = x ile, yani "ters" zaman.

Örneğinizde olan şey budur.data ile

Parser f <*> Parser x = Parser h where ... 

, tartışmaların ya ise <*> tanımında desen maçı hemen sapmak, ancak newtype ile kurucular dikkate alınmaz ve bu size yazdığım gibi eğer olduğunu

yalnızca x = ⊥ için ayrılacaksa x talep edilir.

+0

Hala net olmadığım iki şey 1) desen eşleştirme farkının Haskell'in semantiği tarafından gerekip gerekmediği ve 2) desen eşleştirme farkının yapıcının katılık farkından kaynaklanıp kaynaklanmadığı. –

+0

@MattFenwick: 1) Evet, yeni yazımlar temel olarak semantik olarak mevcut olmadığından, bir tanesinde desen eşlemesi altta yatan türdeki desen eşleşmesiyle aynıdır, bu nedenle x 'modeli x' değerini değerlendirmediğinden desen 'N x'. 2) Hayır. Verileri göz önünde bulundurun S a = S! A; constS x (S y) = x', sonra '' 'un tanımsız' seq' x = ⊥'' ve 'constS x ⊥ = ⊥'. – hammar

+0

Bir veri yapıcısı durumunda, derleyicinin kurucunun desene uyup uymadığını tespit etmek için yeterince değerlendirmesi gerekir? –

10

data ve newtype arasındaki fark, data'un "kaldırılması" ve newtype'un olmamasıdır. Bu, data'un ekstra ⊥ anlamına geldiği anlamına gelir - bu durumda, undefined/= Parser undefined anlamına gelir. Applicative kod düzeniniz Parser x ile eşleştiğinde, yapıcı varsa değerini zorlar.

data yapıcısında model eşleştirmesi yaptığınızda, bunun make olmadığından emin olmak için değerlendirilir ve ayrıştırılır. Örneğin:

λ> data Foo = Foo Int deriving Show 
λ> case undefined of Foo _ -> True 
*** Exception: Prelude.undefined 

Yani bir data yapıcı üzerindeki desen eşleştirme sıkı olduğunu ve bunu zorlayacaktır. Diğer yandan, bir newtype, yapıcının sardığı tiple tam olarak aynı şekilde temsil edilir. Yani bir newtype yapıcı eşleşen kesinlikle hiçbir şey yapar:

kilitlenmesine değil içermeyecek şekilde data programı değiştirmek için iki yol muhtemelen vardır
λ> newtype Foo = Foo Int deriving Show 
λ> case undefined of Foo _ -> True 
True 

. Bunlardan biri, her zaman "başarılı" olacak Applicative örneğinizde reddedilemez bir desen eşleşmesi kullanmak olacaktır (ancak daha sonraki herhangi bir zamanda başarısız olabilecek eşleşen değerleri kullanarak). Her newtype eşleşmesi, reddedilemez bir desen gibi davranır (eşleşecek sıkı bir kurucu olmadığı için).

λ> data Foo = Foo Int deriving Show 
λ> case undefined of ~(Foo _) -> True 
True 

diğer undefined yerine Parser undefined kullanmak olacaktır:

λ> case Foo undefined of Foo _ -> True 
True 

Bu maçı başarılı olur, üzerinde eşleşti ediliyor geçerli Foo değer orada çünkü. undefined içeriyor, ancak kullanmadığımızdan bu alakalı değil - sadece en üst kurucuya bakıyoruz.


Verdiğin tüm bağlantılara ek olarak, this article alakalı bulabilir.

İlgili konular