Haskell 我知道如何使用它,但我不知道;我不能确切地理解它是如何做到的(读者monad)
考虑以下代码(忽略明显的部分) 函数“calculateContentLength”具有返回类型(类型为Reader String Int),但没有传入参数。我意识到函数本身只是传递给runReader函数的两个参数之一,但是runReader的第二个参数“s”如何与“calculateContentLength”中的“ask”绑定Haskell 我知道如何使用它,但我不知道;我不能确切地理解它是如何做到的(读者monad),haskell,monads,reader-monad,Haskell,Monads,Reader Monad,考虑以下代码(忽略明显的部分) 函数“calculateContentLength”具有返回类型(类型为Reader String Int),但没有传入参数。我意识到函数本身只是传递给runReader函数的两个参数之一,但是runReader的第二个参数“s”如何与“calculateContentLength”中的“ask”绑定 换句话说,“calculateContentLength”如何“知道”(并访问)使用“runReader”传递的第二个参数?让我们看看定义读取器的一种方法 newt
换句话说,“calculateContentLength”如何“知道”(并访问)使用“runReader”传递的第二个参数?让我们看看定义
读取器的一种方法
newtype Reader r a = Reader { runReader :: r -> a }
所以Reader
是一个接受函数的构造函数。该函数接受类型为r
的环境,并返回类型为a
的结果
ask = Reader { runReader = \env -> env }
ask = Reader id
return
操作只是忽略环境并返回一个值
return x = Reader { runReader = \_ -> x }
m>>=n
操作执行简单的排序:它获取环境,在该环境中运行m
,然后在同一环境中运行n
,并将m
的结果传递给它
m >>= n = Reader $ \env -> let
a = runReader m env
in runReader (n a) env
现在我们可以拿你的例子,去糖,一步一步地减少
calculateContentLength = do
content <- ask
return (length content)
-- substitute definition of 'ask'
calculateContentLength = do
content <- Reader id
return (length content)
-- substitute definition of 'return'
calculateContentLength = do
content <- Reader id
Reader (\_ -> length content)
-- desugar 'do' into '>>='
calculateContentLength =
Reader id >>= \content -> Reader (\_ -> length content)
-- definition of '>>='
calculateContentLength = Reader $ \env -> let
a = runReader (Reader id) env
in runReader ((\content -> Reader (\_ -> length content)) a) env
-- reduce lambda
calculateContentLength = Reader $ \env -> let
a = runReader (Reader id) env
in runReader (Reader (\_ -> length a)) env
-- definition of 'runReader'
calculateContentLength = Reader $ \env -> let
a = id env
in runReader (Reader (\_ -> length a)) env
-- definition of 'id'
calculateContentLength = Reader $ \env -> let
a = env
in runReader (Reader (\_ -> length a)) env
-- remove redundant variable
calculateContentLength = Reader $ \env
-> runReader (Reader (\_ -> length env)) env
-- definition of 'runReader'
calculateContentLength = Reader $ \env -> (\_ -> length env) env
-- reduce
calculateContentLength = Reader $ \env -> (length env)
calculateContentLength = Reader length
calculateContentLength=do
内容>=\content->Reader(\\内容->长度)
--“>>=”的定义
calculateContentLength=Reader$\env->let
a=runReader(读卡器id)环境
在runReader((\content->Reader(\ \ \ \->length content))a)环境中
--降低λ
calculateContentLength=Reader$\env->let
a=runReader(读卡器id)环境
在runReader(读卡器(\ \ \->长度a))环境中
--“runReader”的定义
calculateContentLength=Reader$\env->let
a=id环境
在runReader(读卡器(\ \ \->长度a))环境中
--“id”的定义
calculateContentLength=Reader$\env->let
a=环境
在runReader(读卡器(\ \ \->长度a))环境中
--删除冗余变量
calculateContentLength=读取器$\env
->runReader(读卡器(\ \ \->length env))env
--“runReader”的定义
calculateContentLength=Reader$\env->(\ \ \ \->length env)env
--减少
calculateContentLength=读取器$\env->(长度env)
calculateContentLength=读卡器长度
现在应该更容易看到runReader calculateContentLength
与length
是如何相同的,以及ask
是如何不神奇的monad的>=
操作构建了一个函数,当您使用runReader
运行计算时,它会隐式地为您传递环境
newtype Reader r a = Reader { runReader :: r -> a }
实际上,Reader
是根据ReaderT
定义的,它使用一元操作而不是纯函数,但其实现形式基本相同。顺便说一句,我肯定会涉及到咖喱,但我只是看不清楚细节。我鼓励您使用runReader
和ask
的源代码来证明简单的等式runReader ask s=s
。然后看看你是否可以用这个证明作为直觉的燃料。谢谢你——我完全忘记了函数开头的“do”。所以我错过了整个装订部分。这就是为什么我看不到发生了什么。谢谢你的详细解释。
calculateContentLength = do
content <- ask
return (length content)
-- substitute definition of 'ask'
calculateContentLength = do
content <- Reader id
return (length content)
-- substitute definition of 'return'
calculateContentLength = do
content <- Reader id
Reader (\_ -> length content)
-- desugar 'do' into '>>='
calculateContentLength =
Reader id >>= \content -> Reader (\_ -> length content)
-- definition of '>>='
calculateContentLength = Reader $ \env -> let
a = runReader (Reader id) env
in runReader ((\content -> Reader (\_ -> length content)) a) env
-- reduce lambda
calculateContentLength = Reader $ \env -> let
a = runReader (Reader id) env
in runReader (Reader (\_ -> length a)) env
-- definition of 'runReader'
calculateContentLength = Reader $ \env -> let
a = id env
in runReader (Reader (\_ -> length a)) env
-- definition of 'id'
calculateContentLength = Reader $ \env -> let
a = env
in runReader (Reader (\_ -> length a)) env
-- remove redundant variable
calculateContentLength = Reader $ \env
-> runReader (Reader (\_ -> length env)) env
-- definition of 'runReader'
calculateContentLength = Reader $ \env -> (\_ -> length env) env
-- reduce
calculateContentLength = Reader $ \env -> (length env)
calculateContentLength = Reader length