Szukanie konstruktywnej krytyki przy realizacji monad
Uczę się monad, to moja pierwsza robocza (poza trywialną monadą). Możesz bezlitośnie krytykować wszystko w nim. Szczególnie interesują mnie odpowiedzi" bardziej idiomatyczne "i" bardziej eleganckie".
Monada ta liczy liczbę wykonanych wiązań.data C a = C {value :: a, count :: Int} deriving (Show)
instance Monad C where
(>>=) (C x c) f = C (value $ f x) (c + 1)
return x = C x 0
add :: (Num a) => a -> a -> C a
add x y = return $ x + y
-- Simpler way to do this? foldM is obviously something different.
mysum [x] = return x
mysum (x:xs) = mysum xs >>= add x
1 answers
Stylistycznie to jest bardzo ładne. W realnym świecie spodziewałbym się 60% szansy na taką notację zamiast tej, którą dałeś: {]}
C x c >>= f = C (value $ f x) (c + 1)
Ale To jest tak niewielkie, że nie warto o tym wspominać.
Mówiąc poważniej, nie stylistycznie, ale semantycznie: to nie jest monada. W rzeczywistości, to narusza wszystkie trzy prawa monad.
(1) return x >>= f = f x
(2) m >>= return = m
(3) m >>= (f >=> g) = (m >>= f) >>= g
(gdzie (>=>)
jest zdefiniowane jako f >=> g = \x -> f x >>= g
. Jeśli (>>=)
jest operatorem "aplikacji", to {[7] } jest odpowiednim składem centrala. Lubię określać trzecie prawo używając tego operatora, ponieważ wydobywa ono znaczenie trzeciego prawa: Asocjacja.)
Z tymi obliczeniami:
(1):
return 0 >>= return
= C 0 0 >>= return
= C (value $ return 0) 1
= C 0 1
Not equal to return 0 = C 0 0
(2):
C 0 0 >>= return
= C (value $ return 0) 1
= C 0 1
Not equal to C 0 0
(3)
C 0 0 >>= (return >=> return)
= C (value $ (return >=> return) 0) 1
= C (value $ return 0 >>= return) 1
= C (value $ C 0 1) 1
= C 0 1
Is not equal to:
(C 0 0 >>= return) >>= return
= C (value $ return 0) 1 >>= return
= C 0 1 >>= return
= C (value $ return 0) 2
= C 0 2
To nie jest tylko błąd w Twojej implementacji - nie ma monady, która "zlicza liczbę bindów". To musi naruszać prawa (1) i (2). Fakt, że Twoje narusza prawo (3) jest jednak błędem implementacji.
The trouble czy f
w definicji (>>=)
może zwrócić akcję, która ma więcej niż jedno bind, a Ty to ignorujesz. Musisz dodać liczbę bindów z lewego i prawego argumentu:
C x c >>= f = C y (c+c'+1)
where
C y c' = f x
To poprawnie policzy liczbę wiązań i spełni trzecie prawo, którym jest prawo asocjacji. To nie zadowoli pozostałych dwóch. Jeśli jednak odrzucisz +1
z tej definicji, to uzyskasz rzeczywistą monadę, która jest równoważna Writer
monada nad +
monoidem. To w zasadzie sumuje wyniki wszystkich subkomputacji. Możesz użyć tego do policzenia liczby somethings, po prostu nie wiąże -- bind jest zbyt specjalny, aby zliczyć. Ale, na przykład:
tick :: C ()
tick = C () 1
Następnie C
policzy liczbę tick
S, które wystąpiły w obliczeniach.
W rzeczywistości, można zastąpić Int
dowolnym typem i (+)
dowolnym operatorem asocjacyjnym i uzyskać monadę. Tym właśnie jest Writer
monada ogólnie. Jeśli operator nie jest asocjacyjny, to zawiedzie trzecie prawo (czy widzisz dlaczego?).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-11 08:30:03