我试图了解读者和/或州monad的实际需求.我见过的所有例子(包括很多关于stackoverflow,因为我已经寻找合适的例子,我可以使用以及各种书籍和博客文章)的形式(伪代码)
f = do
foo <- ask
do something with foo
g = do
foo <- ask
do something else using foo
h = runReader
(
f
g
)
Run Code Online (Sandbox Code Playgroud)
换句话说,调用两个函数并(可能)从一个调用到下一个调用保持某种状态.但是,我没有发现这个例子特别令人信服,因为(我认为)我可以让f返回一些状态,然后将该状态传递给g.
我希望看到一个例子,使用一个整数(比如说)作为要保留的状态,而不是两个顺序调用f然后从中心位置调用g,而不是调用f然后在内部调用g然后在主程序中更改了状态(如果状态monad).
我见过的大多数(实际上是所有)示例花费了大量时间专注于monad的定义,然后展示如何设置单个函数调用.对我来说,这就是能够进行嵌套调用并让状态随身携带,以证明它为什么有用.
这个问题关系到这一个,在那里我是想了解如何使用读者单子Scala中.
在答案中,autor使用以下代码获取以下实例ReaderInt[String]:
import scalaz.syntax.applicative._
val alwaysHello2: ReaderInt[String] = "hello".point[ReaderInt]
Run Code Online (Sandbox Code Playgroud)
Scala使用哪种机制来解析表达式的类型,"hello".point[ReaderInt]以便它使用正确的point函数?
这是一个简单的服务示例,其方法返回reader:
trait Service1_1{
def s1f1:Reader[Map[String,Int],Int] =
Reader(_("name"))
def s1f2:Reader[Map[String,Int],Int] =
Reader(_("age"))
}
Run Code Online (Sandbox Code Playgroud)
这是一个服务使用者,它接受参数,映射并返回读取器本身:
trait Service1_2 {
def s12f1(i:Int, map:Map[String,Int]):Reader[Service1_1, Int] =
Reader(s => {
val r = for {
r1 <- s.s1f1
r2 <- s.s1f2
} yield r1 + r2
r.run(map) + i
})
}
Run Code Online (Sandbox Code Playgroud)
好的,要使用Service1_2.s12f1,我必须在参数列表中具有map:
object s1 extends Service1_1
object s2 extends Service1_2
val r = s2.s12f1(3, Map("age"-> 1, "name"-> 2)).run(s1)
Run Code Online (Sandbox Code Playgroud)
问题:如何实施Service1_2.s12f2:
trait Service1_2 {
def s2f2 = ???
}
Run Code Online (Sandbox Code Playgroud)
为了能够像这样运行它:
s2.s2f2(2)
.run(s1)
.run(Map("age"-> 1, "name"-> 2)) …Run Code Online (Sandbox Code Playgroud) dependency-injection scala composition reader-monad scala-cats
考虑以下代码(省略明显的部分)
main = do
let s = "123456";
let len = runReader calculateContentLength s
putStrLn $ "Original 's' length: " ++ (show len)
calculateContentLength :: Reader String Int
calculateContentLength = do
content <- ask -- this seems to be the same as 'reader id'
return (length content);
Run Code Online (Sandbox Code Playgroud)
'ask'如何获取字符串参数?这是我的理解,因为类型声明
calculateContentLength :: Reader String Int
Run Code Online (Sandbox Code Playgroud)
函数'calculateContentLength'有一个返回类型(类型为Reader String Int),但它没有传入的参数.我意识到函数本身只是传递给runReader函数的两个参数之一,但是runReader的第二个参数's'与'calculateContentLength'中的'ask'有什么关联?
换句话说,'calculateContentLength'如何"知道"关于(并获取访问)传递给'runReader'的第二个参数?
在我的项目的其他地方,我已经定义了一个walk遍历AST 的函数,该函数的核心用于foldl将访问树中每个节点的结果减少为单个幺半群结果(例如,从特殊结果生成"符号表")树中的节点).
我的问题是:是否可以将这两种方法结合起来并使用像我的函数这样的walk函数:
walk :: Monoid a => (Node -> a) -> a -> Node -> a
walk f acc n = foldl (walk f) (acc <> f n) children
where
children = case n of
Blockquote b -> b
DocBlock d -> d
FunctionDeclaration {} -> functionBody n
List l -> l
ListItem i -> i …Run Code Online (Sandbox Code Playgroud) import cats.data.ReaderT
import cats.instances.either._
trait Service1
trait Service2
case class Cats(name:String)
type FailFast[A] = Either[List[String], A]
type Env = (Service1, Service2, Cats)
type ReaderEnvFF[A] = ReaderT[FailFast, Env, A]
def toReaderEnvFF[A](input:A):ReaderEnvFF[A] =
ReaderT((_:Env) => Right(input))
def c:ReaderEnvFF[Cats] =
for {
cats <- toReaderEnvFF((_:Env)._3)
} yield cats // This line is 26
Run Code Online (Sandbox Code Playgroud)
错误:
错误:(26,11)类型不匹配;找到:T1.this.Env => com.savdev.Cats(展开为)(((com.savdev.Service1,com.savdev.Service2,com.savdev.Cats)))=> com.savdev.Cats需要的猫:com .savdev.Cats}产生猫
您能解释一下,为什么猫不是com.savdev.Cats吗?以及为什么在错误中说它被扩展为具有return方法的功能[Cats],而不是botFailFast[Cats]
我尝试应用与此处完全相同的逻辑:
trait Service1 { def s1f = Option(10) }
trait Service2 {
type ReaderS1[A] = ReaderT[Option,Service1,A]
import cats.syntax.applicative._ …Run Code Online (Sandbox Code Playgroud) type MapReaderOrOption[A] = ReaderT[Option, Map[String,String], A]
Run Code Online (Sandbox Code Playgroud)
我可以从创建它ReaderT.apply:
def f:MapReaderOrOption[Int] = ReaderT(_ => Option(10))
Run Code Online (Sandbox Code Playgroud)
从A类型通过类型丰富和纯方法:
import cats.Applicative
import cats.syntax.int._
def f:MapReaderOrOption[Int] = 10.pure[MapReaderOrOption]
Run Code Online (Sandbox Code Playgroud)
我想找到类似的东西。每次使用ReaderT(..)都不那么方便。当然,我可以创建一个辅助方法。问题是,还有其他选择吗?
预期类似:
def f:MapReaderOrOption[Int] = Option(10).asReaderT[MapReaderOrOption]
Run Code Online (Sandbox Code Playgroud) 我正在玩Purescript中的Reader monad,我遇到了一个奇怪的行为.我不知道是不是因为我对这个monad缺乏理解,或者我错过了其他的东西.
这是我的代码:
type Level = Number
type Doc = Reader Level String
renderLine :: String -> Level -> String
renderLine s 0 = s
renderLine s l = "\t" ++ (renderLine s (l - 1))
line :: String -> Doc
line s = do
level <- ask
return (renderLine s level)
Run Code Online (Sandbox Code Playgroud)
这没关系,会编译.不过,在此之前我在我的功能行中尝试了一些更简单的方法:
line :: String -> Doc
line s = do
level <- ask
return "Hello Reader monad"
Run Code Online (Sandbox Code Playgroud)
尽管(renderLine s level)和"Hello Reader monad"具有相同的类型,但它不会编译.它会抛出这个错误:"找不到Control.Monad.Reader.Class.MonadReader u14555(Control.Monad.Reader.Trans.ReaderT Prim.Number Control.Monad.Identity.Identity)的实例"
我确定我错过了什么,但我不知道是什么.
我试图理解读者monad但似乎无法理解bind(>> =)在这个monad中的作用.
这是我正在分析的实现:
newtype Reader e a = Reader { runReader :: (e -> a) }
instance Monad (Reader e) where
return a = Reader $ \e -> a
(Reader r) >>= f = Reader $ \e -> runReader (f (r e)) e
Run Code Online (Sandbox Code Playgroud)
(Reader r)而不是(Reader r a).(f (r e))什么:它的目的是什么?非常感谢帮助我.
我想学习,如何使用Reader Monad.不幸的是,只有少量示例代码可用
我想创建一个Reader,其中包含环境和重新获取的值Int.我定义了这样的类型:
type IntRead = Reader Int Int
Run Code Online (Sandbox Code Playgroud)
我试过的代码是这样的:
addStuff :: Reader Int Int
addStuff = do
a <- (*2)
b <- (+10)
return (a+b)
Run Code Online (Sandbox Code Playgroud)
我得到一个错误,因为ReaderT是预期的.如何addStuff使用Reader Monad 创建一个函数?我应该在哪里为此功能提供环境?
我一直试图掌握读者monad并且遇到了这个教程.在其中,作者提出了这个例子:
example2 :: String -> String
example2 context = runReader (greet "James" >>= end) context
where
greet :: String -> Reader String String
greet name = do
greeting <- ask
return $ greeting ++ ", " ++ name
end :: String -> Reader String String
end input = do
isHello <- asks (== "Hello")
return $ input ++ if isHello then "!" else "."
Run Code Online (Sandbox Code Playgroud)
我知道这是一个显示机制的简单例子,但我想弄清楚为什么它比做类似的东西更好:
example3 :: String -> String
example3 = end <*> (greet "James")
where
greet …Run Code Online (Sandbox Code Playgroud) newtype Reader e a = R { runReader :: e -> a }
instance Monad (Reader e) where
return a = R $ \_ -> a
m >>= k = R $ \r -> runReader (k (runReader m r)) r
Run Code Online (Sandbox Code Playgroud)
我很难理解这两个片段.我可以说第一个是读者的记录语法描述,它具有从e到a的函数runReader,但第二个让我困惑.
通过将m与k绑定,它实际上是在尝试创建一个新的Reader,但是如何实现
runReader (k (runReader m r)) r
Run Code Online (Sandbox Code Playgroud)
锻炼?我认为runReader只接受一个参数,但现在它似乎正在接受两个,一个是k(runReader mr)而另一个是r.
提前致谢.
我有一个带有单元测试的无标签最终实现,当我运行单元测试时,仅第一步被调用,其余部分不被调用。
这是测试目标:
class NameThing[F[_]: Monad](implicit console: Console[F]) {
def program: F[Unit] = for {
_ <- console.prompt
rawName <- console.read
fullName = parse(rawName)
_ <- console.display(fullName)
} yield ()
def parse(rawName:String):FullName = {
val parts = rawName.split(" ")
FullName(parts(0), parts(1))
}
}
Run Code Online (Sandbox Code Playgroud)
单元测试是:
implicit object TestConsole extends Console[Test] {
override def prompt: Test[Unit] = {
println("ok1")
Reader(TestEnv => TestEnv.prompt)
}
override def read: Test[String] = {
println("ok2")
Reader(TestEnv => TestEnv.read)
}
override def display(fullName: FullName): Test[Unit] = {
println("ok3")
Reader(TestEnv …Run Code Online (Sandbox Code Playgroud) functional-programming scala for-comprehension reader-monad scala-cats
reader-monad ×13
haskell ×7
monads ×5
scala ×5
scala-cats ×4
applicative ×1
composition ×1
fold ×1
parsec ×1
purescript ×1
scalaz ×1
state-monad ×1