Bunu anlamanın en iyi yolu bunu yapmaktır. Aşağıda bir uygulama var foldlM
kullanarak foldl
yerine foldr
. İyi bir alıştırma, deneyin ve daha sonra önereceğim çözüme gelin. Örnek, bunu başarmak için yaptığım tüm nedenleri açıklıyor, bu sizinkinden farklı olabilir ve önyargı olabilir, çünkü zaten bir fonksiyon akümülatörü kullanmayı biliyordum.
1. Adım : Yazım foldlM
açısındanfoldl
-- this doesn't compile because f returning type is (m b) and not just (b)
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldl f z0 xs
-- So let substitute f by some undefined f'
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldl f' z0 xs
where f' = undefined
-- cool, but f' should use f somehow in order to get the monadic behaviour
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldl f' z0 xs
where f' b a = f somethingIDontkNow
Burada f'
bunun saf olduğunu fark edersiniz f
ve tür eşleşmesinin sonucunu çıkarmanız gerekir . Monadik bir değeri 'çıkarmanın' tek yolu >>=
operatöre aittir , ancak böyle bir operatörün kullanıldıktan hemen sonra sarılması gerekir.
Sonuç olarak: Ne zaman bitirirseniz bu monad'ı tamamen açmak istiyorum , sadece pes et. Doğru yol değil
Adım 2 : Hadi yazma için deneyin foldlM
açısından foldl
ama ilk kullanan []
katlanabilir olarak, bu (yani biz aslında kullanımına gerek yoktur desen maç kolaydır çünkü fold
)
-- This is not very hard. It is pretty standard recursion schema. :)
foldlM' :: (Monad m) => (b -> a -> m b) -> b -> [a] -> m b
foldlM' f z0 [] = return z0
foldlM' f z0 (x:xs) = f z0 x >>= \c -> foldlM' f c xs
Tamam, bu kolaydı. foldl
Tanımı listeler için normal tanımla karşılaştıralım
foldlM' :: (Monad m) => (b -> a -> m b) -> b -> [a] -> m b
foldlM' f z0 [] = return z0
foldlM' f z0 (x:xs) = f z0 x >>= \c -> foldlM' f c xs
myfoldl :: (b -> a -> b) -> b -> [a] -> b
myfoldl f z0 [] = z0
myfoldl f z0 (x:xs) = foldl f (f z0 x) xs
Güzel!! hemen hemen aynı. Önemsiz olay da aynı şeyle ilgilidir. Özyinelemeli durum daha böyle bir şey yazmak istiyorum, biraz farklıdır: foldlM' f (f z0 x) xs
. Ancak adım 1'deki gibi derlenmez, bu yüzden Tamam, uygulamak istemiyorum f
, sadece böyle bir hesaplama yapmak ve onu oluşturmak için>>=
düşünebilirsiniz . DahafoldlM' f (f z0 x >>=) xs
mantıklıymış gibi bir şey yazmak istiyorum ...
Adım 3 Biriktirmek istediğiniz şeyin bir sonuç değil, bir fonksiyon kompozisyonu olduğunu anlayın. ( burada muhtemelen zaten yayınladığınız için zaten bildiğim gerçeği ile yanlıyorum ).
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldl f' initFunc xs
where initFunc = undefined :: b -> m b
f' = undefined :: (b -> m b) -> a -> (b -> m b) -- This type signature can be deduce because f' should be applied to initFunc and a's from t a.
initFunc
Adım 2'den (özyinelemeli tanım) elde ettiğimiz bilginin türü ve kullanımı ile bunu çıkarabiliriz initFunc = return
. Tanımı f'
bilerek tamamlanabilir f'
kullanmalıdır f
ve >>=
.
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldl f' return xs z0
-- ^^^^^^
-- |- Initial value
where f' b a = \bvalue -> b bvalue >>= \bresult -> f bresult a -- this is equivalent to (b >=> \result -> f result a) which captures the sequence behaviour of the implementation
-- ^ ^^^^^^ ^^^^^^^
-- | | |- This is the result of previous computation
-- | |- f' should return a function b -> m b. Any time you have to return a function, start writing a lambda
-- |- This b is the accumulated value and has type b -> m b
-- Following the types you can write this with enough practise
Gördüğünüz gibi, bunu yapmak çok zor değil. Uygulamaya ihtiyacı var, ama profesyonel bir haskell geliştiricisi değilim ve kendim yapabilirim, bu bir pratik meselesi