Okuyucu Amaç Monad
Haskell için çaylağım. Okuyucu Monad birkaç kez, ama yine de Okuyucu Monad amacı ne anlamıyorum okudum. Okuyucu Monad çok karmaşık ve işe yaramaz gibi görünüyor. Java veya C gibi zorunlu dil , okuyucu monad eğer yanılmıyorsam () için eşdeğer bir terim yok. Bana basit bir örnek ver ve bana biraz daha açık konuşabilir misin. Benim cehalet için özür dilerim.
CEVAP
Korkma! Okuyucu monad aslında o kadar da karışık değil ve kullanımı kolay gerçek bir yardımcı vardır.
Bir monad yaklaşan iki yolu vardır: sorabiliriz
- Bu monad nediryapın? İşlemleri ile donatılmış nedir? Bunun neresi güzel ki?
- Monad nasıl uygulanır? Nereden doğar?
İlk yaklaşım, okuyucu monad soyut bir türüdür
data Reader env a
bu . böyle
-- Reader is a monad
instance Monad (Reader env)
-- and we have a function to get its environment
ask :: Reader env env
-- finally, we can run a Reader
runReader :: Reader env a -> env -> a
Bunu nasıl kullanırız? Peki, okuyucu monad geçen (örtülü) için iyi bir hesaplama ile bilgi yapılandırma.
Her zaman bir "sabit" bir hesaplama ihtiyacınız olan en çeşitli noktalarda, ama gerçekten senin gibi yapabilmek aynı hesaplama ile farklı değerleri, daha sonra kullanmak bir okuyucu monad.
Okuyucu monadlar da OO insanlar dependency injection çağrı ne için kullanılır. Örneğin, negamax algoritma sık (çok iyi optimize edilmiş formları), iki kişilik oyunda bir pozisyon değerini hesaplamak için kullanılır. Algoritma kendisi olsa umurunda değil ne oyun oynuyor, bunun dışında ihtiyaç belirleme ne "ileri" pozisyon oyunu ve ihtiyacınız yapabilmek için geçerli konumu bir zafer pozisyon.
import Control.Monad.Reader
data GameState = NotOver | FirstPlayerWin | SecondPlayerWin | Tie
data Game position
= Game {
getNext :: position -> [position],
getState :: position -> GameState
}
getNext' :: position -> Reader (Game position) [position]
getNext' position
= do game <- ask
return $ getNext game position
getState' :: position -> Reader (Game position) GameState
getState' position
= do game <- ask
return $ getState game position
negamax :: Double -> position -> Reader (Game position) Double
negamax color position
= do state <- getState' position
case state of
FirstPlayerWin -> return color
SecondPlayerWin -> return $ negate color
Tie -> return 0
NotOver -> do possible <- getNext' position
values <- mapM ((liftM negate) . negamax (negate color)) possible
return $ maximum values
Bu daha sonra herhangi bir sonlu ile, deterministik çalışacak, iki kişilik bir oyun.
Bu desen bile gerçekten bağımlılık enjeksiyon olmayan şeyler için yararlıdır. Size mali işlerde sanırım, tüm iyi ve güzel olan bir varlık (türev) söylemek, fiyatlandırma için biraz karmaşık mantık tasarımı ve kokuşmuş bir monadlar olmadan yapabilirsiniz. Ama sonra, birden fazla para birimi ile başa çıkmak için programınızı değiştirin. Sinek de para birimleri arasında dönüştürme gerekir. İlk denemen üst düzey bir fonksiyon tanımlamaktır
type CurrencyDict = Map CurrencyName Dollars
currencyDict :: CurrencyDict
spot fiyatlar almak için. Daha sonra kodunuzda bu sözlük çağırabilirsiniz....ama bekleyin! İşe yaramaz! Para birimi sözlük sabittir ve bu yüzden sadece aldığı zaman programınızı hayat için, ama aynı olmalıderlenmiş! Sen ne yapıyorsun Peki? İyi bir seçenek Okuyucu monad kullanmak olacaktır:
computePrice :: Reader CurrencyDict Dollars
computePrice
= do currencyDict <- ask
--insert computation here
Belki de-case kullanmak en klasik tercümanlar uygulanması. Ama bakmadan önce, başka bir işlevi tanıtmak istiyoruz
local :: (env -> env) -> Reader env a -> Reader env a
Tamam, Haskell ve diğer fonksiyonel diller lambda calculus dayanmaktadır. Lambda calculus gibi görünen bir sözdizimi vardır
data Term = Apply Term Term | Lambda String Term | Var Term deriving (Show)
ve bu dil için bir değerlendiricisi yazmak istiyoruz. Bunu yapmak için, bağlama maddeleri (aslında statik ölçüm yapmak istiyorum çünkü kapaklar) ile ilgili bir liste olan bir ortam, takip etmek gerekir.
newtype Env = Env ([(String,Closure)])
type Closure = (Term,Env)
İşimiz bittiğinde bir değer (veya hata) dışarı çıkalım:
data Value = Lam String Closure | Failure String
Yani, yorumlayıcı yazmak sağlar:
interp' :: Term -> Reader Env Value
--when we have lambda term, we can just return it
interp' (Lambda nv t)
= do env <- ask
return $ Lam nv (t,env)
--when we run into a value we look it up in the environment
interp' (Var v)
= do (Env env) <- ask
case lookup (show v) env of
-- if it is not in the environment we have a problem
Nothing -> return . Failure $ "unbound variable: " (show v)
-- if it is in the environment, than we should interpret it
Just (term,env) -> local (const env) $ interp' term
--the complicated case is an application
interp' (Apply t1 t2)
= do v1 <- interp' t1
case v1 of
Failure s -> return (Failure s)
Lam nv clos -> local (\(Env ls) -> Env ((nv,clos):ls)) $ interp' t2
--I guess not that complicated!
Son olarak, önemsiz bir çevre geçirerek kullanabiliriz:
interp :: Term -> Value
interp term = runReader (interp' term) (Env [])
İşte bu kadar. Lambda calculus için tamamen işlevsel bir tercüman.
Yani, bunu düşünmek için başka bir yol sormak: nasıl uygulanıyor? İyi cevap okuyucu monad aslında tüm monadlar ve en gösterişli en basit biridir.
newtype Reader env a = Reader {runReader :: env -> a}
Okuyucu sadece fonksiyonlar için süslü bir isim. Zaten runReader
API diğer parçalar ne olacak tanımladık? Her Monad
Functor
: bir
instance Functor (Reader env) where
fmap f (Reader g) = Reader $ f . g
Şimdi, bir monad almak için:
instance Monad (Reader env) where
return x = Reader (\_ -> x)
(Reader f) >>= g = Reader $ \x -> runReader (g (f x)) x
o kadar korkunç değil. ask
gerçekten basittir:
ask = Reader $ \x -> x
local
o kadar da kötü değil.
local f (Reader g) = Reader $ \x -> runReader g (f x)
Tamam, okuyucu monad sadece bir fonksiyonudur. Neden Okuyucu var mı? Güzel soru. Aslında, gerek yok!
instance Functor ((->) env) where
fmap = (.)
instance Monad ((->) env) where
return = const
f >>= g = \x -> g (f x) x
Bu daha basit. Daha fazla, ask
id
local
sadece diğer sırada işlevi kompozisyon!
Okuyucu Bağımlılık Enjeksiyon için Mon...
'değişken' anahtar kelime he...
Amaç ayıklama pdf metin C...
Zaten açık bir veri okuyucu öncelikle ...
Amaç dize dize dizideki arama c...