haskell - 理解 Monad 变形金刚的困难

标签 haskell functional-programming monads monad-transformers

我希望获得一些有助于理解 Monad Transformers 的输入,以及与此相关的使用 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

据我了解,Protected 类型描述了一些protected 数据,这些数据存储在共享环境 (Reader) 中并且属于也许(MaybeT)

我在类型变量 sa 方面遇到问题:

  • s是否描述了 protected 数据的字符串(密码),a protected 数据的类型?
  • s 是否描述了 protected 数据的类型,如果是,是什么 一个描述?

在函数运行中:

run :: ProtectedData s -> Protected s a -> Maybe a
run ps psa = runReader (runMaybeT psa) ps

据我了解,Protected 中的 ReaderProtectedData 上运行,以返回值。

这只留下函数access:

access :: String -> Protected a a
access pass = do  
                pd <- lift ask
                let v = accessData pass pd
                MaybeT $ return v

最让我头疼的是哪个。首先,我在把握效果和结果方面遇到了问题。

  • 此函数是否用于将密码和数据注入(inject)Reader
  • 是否用于访问数据并在输入错误密码时失败?

其次我无法理解第一行

pd <- lift ask
  • 我明白,ask 用于访问共享环境 通过 Reader,但为什么我必须将它 liftMaybeT 才能获得 它里面的实际值(value)?

最佳答案

As i understand it the Protected type describes some "protected" Data

没有。 Protected s a 应被视为返回类型 a 值的程序 类型。在计算过程中,程序对 s 类型的 secret 值具有只读访问权限,并且只有当它“知道”正确的密码时。

这样的 secret 值,与其密码配对,类型为ProtectedData s

does s describe the type of the protected Data, and if so, what does a describe?

是的。这里 a 是程序结果的通用类型。

举个例子,你可以考虑密码是 String 的情况(它必须是,在你的代码中字符串类型是硬编码的)并且 secret 值的类型是 s = 整数。然后您编写一个访问 secret 整数的程序,并检查它是否为正数,并返回一个 Bool。这里,a = Bool

请注意,我稍微简化了场景。由于我们还使用了 MaybeT,因此我们正在对一个程序建模,该程序并不总是返回 a 类型的值,但也可能会失败。使用错误的密码可能会导致失败。在这种情况下,MaybeT 会在执行过程中粗略地中止程序。

签名

access :: String -> Protected a a

如果我们把它写成可能会更好理解

access :: String -> Protected s s

显示它是一个帮助函数来访问 secret 值(或失败),给定密码尝试。它的用法如下:

myProg :: Protected Int Bool
myProg = do
  v <- access "123456"  -- try accessing the protected int
  return (v > 0)

如果密码错误,上面的代码会导致失败(run会返回Nothing)

> run (ProtectedData "actual password" 42) myProg
Nothing

如果密码正确,它会产生正确的 bool 值:

> run (ProtectedData "123456" 42) myProg
Just True

此处Just表示密码正确,True表示 protected Int为正。

关于haskell - 理解 Monad 变形金刚的困难,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69063768/

相关文章:

haskell - 独立的 Haskell Executable 可以在具有相同操作系统的机器上运行吗?

parsing - 使用 Free Monad 实现词法分析器

haskell 单子(monad) : IO [Double] to [IO Double]

haskell - 将 monad 用于诸如列表操作之类的琐碎任务?

haskell - 推拉窗的一种

haskell - Haskell 中的所有类型类都有范畴论类比吗?

algorithm - 懒惰地生成排列

javascript - 柯里化(Currying)一个接受无限参数的函数

scala - 何时使用单例对象以及何时在 scala 中使用实际对象

haskell - Haskell的forkIO的实现