Sup*_*zel 3 monads haskell functional-programming monad-transformers
我希望获得一些有助于理解 Monad Transformer 的信息,以及与此相关的使用do符号会发生什么。我试图理解的例子如下:
data ProtectedData a = ProtectedData String a
accessData :: String -> ProtectedData a -> Maybe a
accessData s (ProtectedData pass v) =
if s == pass then Just v else Nothing
type Protected s a = MaybeT (Reader (ProtectedData s)) a
-- untangles the monad construction
run :: ProtectedData s -> Protected s a -> Maybe a
run ps psa = runReader (runMaybeT psa) ps
access :: String -> Protected a a
access pass = do
-- ask :: ReaderT (ProtectedData a) Identity (ProtectedData a)
-- lift :: ... -> MaybeT (ReaderT (ProtectedData a) Identity) (ProtectedData a)
pd <- lift ask
-- as i understand it: ask returns the value inside the thing.
-- the left arrow actually applies the monad
let v = accessData pass pd
-- return :: Maybe a -> Reader (ProtectedData a) (Maybe a)
MaybeT $ return v
Run Code Online (Sandbox Code Playgroud)
据我了解,该Protected类型描述了一些受保护的数据,这些数据存储在共享环境 ( Reader) 中并且类型为Maybe (MaybeT)。
我在类型变量s和方面遇到问题a:
s描述了受保护数据的字符串(密码)以及a
受保护数据的类型?s描述了受保护数据的类型,如果是,
a描述了什么?在函数运行中:
run :: ProtectedData s -> Protected s a -> Maybe a
run ps psa = runReader (runMaybeT psa) ps
Run Code Online (Sandbox Code Playgroud)
据我了解,Readerfrom insideProtected在 , 上运行ProtectedData以返回值。
只剩下函数access:
access :: String -> Protected a a
access pass = do
pd <- lift ask
let v = accessData pass pd
MaybeT $ return v
Run Code Online (Sandbox Code Playgroud)
这是最让我头疼的一个。首先,我在把握效果和结果方面遇到了问题。
Reader?其次,我无法理解第一行
pd <- lift ask
Run Code Online (Sandbox Code Playgroud)
ask用于通过 访问共享环境Reader,但为什么我必须使用lift它MaybeT来获取其中的实际值?据我了解,受保护类型描述了一些“受保护”数据
No.应该被视为返回 type 值的程序Protected s a的类型。在计算过程中,程序只有在“知道”正确的密码时才能只读访问 类型的秘密值。as
这样的秘密值与其密码配对,其类型为ProtectedData s。
s 是否描述了受保护数据的类型,如果是,a 描述了什么?
是的。这a是程序结果的通用类型。
举个例子,您可以考虑密码为 a String(必须是,在您的代码中字符串类型是硬编码的)并且秘密值的类型为 的情况s = Int。然后编写一个程序来访问秘密整数,并检查它是否为正数,并返回一个Bool. 这里,a = Bool。
请注意,我稍微简化了场景。由于我们也使用MaybeT,因此我们正在建模一个程序,该程序并不总是返回类型的值a,但也可能失败。使用错误的密码可能会导致失败。在这种情况下,MaybeT程序会在执行过程中粗略地中止。
签名
access :: String -> Protected a a
Run Code Online (Sandbox Code Playgroud)
如果我们把它写成
access :: String -> Protected s s
Run Code Online (Sandbox Code Playgroud)
表明它是一个在尝试密码时访问秘密值(或失败)的辅助函数。它的使用方法如下:
myProg :: Protected Int Bool
myProg = do
v <- access "123456" -- try accessing the protected int
return (v > 0)
Run Code Online (Sandbox Code Playgroud)
如果密码错误,上面的代码会导致失败(run会返回Nothing)
> run (ProtectedData "actual password" 42) myProg
Nothing
Run Code Online (Sandbox Code Playgroud)
如果密码正确,它将产生正确的布尔值:
> run (ProtectedData "123456" 42) myProg
Just True
Run Code Online (Sandbox Code Playgroud)
这里Just表示密码正确,True表示保护Int正确。