这是我上一个问题的后续内容
Kleisli定义了两个运算符<=<(compose)和>=>(andThen).在>=>找我很自然的,我不明白怎么<=<会很有用.
而且,看起来没有>=>半群,A => M[A]但是<=<半群确实存在.
它背后的理由是什么?
我遵循了优秀书籍Reactive Domain Modeling的设计,我需要混合Kleisli使用不同的类型:
object CombinedKleisli {
type User = String
type Project = String
trait UserRepo
trait ProjectRepo
trait UserService {
def findByUserId : Kleisli[Future, UserRepo, User]
}
trait ProjectService {
def findProjectById : Kleisli[Future, ProjectRepo, Project]
}
trait ComposedService extends UserService with ProjectService {
for {
user <- findByUserId
project <- findProjectById
} yield (user, project)
}
}
Run Code Online (Sandbox Code Playgroud)
由于类型不对齐,我收到以下编译错误
Error:(28, 15) type mismatch;
found : scalaz.Kleisli[scala.concurrent.Future,domain.service.ServiceTest.ProjectRepo,(domain.service.ServiceTest.User, domain.service.ServiceTest.Project)]
(which expands to) scalaz.Kleisli[scala.concurrent.Future,domain.service.ServiceTest.ProjectRepo,(String, String)]
required: scalaz.Kleisli[scala.concurrent.Future,domain.service.ServiceTest.UserRepo,?]
project …Run Code Online (Sandbox Code Playgroud) 这是 kleisli 组合的常见实现:
kleisli :: Monad m => (a -> m b) -> (b -> m c) -> a -> m c
kleisli = \f g x -> f x >>= g
Run Code Online (Sandbox Code Playgroud)
为什么它不期望 monadic 上下文中的值呢?我相信有一个很好的理由。我只是没能看到它。
kleisli' :: Monad m => (a -> m b) -> (b -> m c) -> m a -> m c
kleisli' = \f g x -> x >>= f >>= g
Run Code Online (Sandbox Code Playgroud)
该类型似乎更易于组合,并且return可以在调用站点上只有纯值的情况下使用。
如果我有以下两个Kleisli箭头:
stdoutProcessA :: Kleisli Maybe String (IO String)
writeToFileA :: Kleisli Maybe (FilePath, String) (IO ())
Run Code Online (Sandbox Code Playgroud)
我希望能够写出像:
compile = proc src -> do
output <- stdoutProcessA -< "..."
writeToFileA -< ("...", output)
...
Run Code Online (Sandbox Code Playgroud)
这当然不起作用,因为String不匹配IO String.另一方面,可以定义两者stdoutProcessA和writeToFileA类型Kleisli IO ...,但是我不能用类型的箭头组合它们Kleisli Maybe ...,这是我需要的其他东西.
我对箭头还不是很有经验,所以我可能会遗漏一些明显的东西.如何进行上述操作?
这个问题的灵感来自我之前提出的问题的反馈
Scalaz为Kleisli[M[_], A, B]函数提供包装类A => M[B].
Kleisli[M[_], A, B]如果M[_]是半群,则是半群.假设这M[_]是一个仿函数.这Kleisli也是一个仿函数是正确的吗?如果M[_]是申请人或单身人士怎么办?
这是我上一个问题的后续行动
我们可以定义一个函数,该函数按路径查找XML节点,(List[String], XmlNode) => Option[XmlNode]作为(String, XmlNode) => Option[XmlNode]按名称获取子节点的函数组合.
我们使用函数A => M[A],其中M是monad,形成a monoid,因此我们可以轻松地组合它们.
现在我想知道是否还有其他有趣的组成这些函数的例子.
我正在尝试使用Kleisli编写返回monad的函数。它适用于Option:
import cats.data.Kleisli
import cats.implicits._
object KleisliOptionEx extends App {
case class Failure(msg: String)
sealed trait Context
case class Initial(age: Int) extends Context
case class AgeCategory(cagetory: String, t: Int) extends Context
case class AgeSquared(s: String, t: Int, u: Int) extends Context
type Result[A, B] = Kleisli[Option, A, B]
val ageCategory: Result[Initial,AgeCategory] =
Kleisli {
case Initial(age) if age < 18 => {
Some(AgeCategory("Teen", age))
}
}
val ageSquared: Result[AgeCategory, AgeSquared] = Kleisli {
case AgeCategory(category, age) => Some(AgeSquared(category, age, age …Run Code Online (Sandbox Code Playgroud) 试图在 Scala 中为一个虚构的 Partial 类型实现 Kleisli 类别(阅读 Bartosz Milewski 的“程序员的类别理论”,这是第 4 章的练习)
object Kleisli {
type Partial[A, B] = A => Option[B]
implicit class KleisliOps[A, B](f1: Partial[A, B]) {
def >=>[C](f2: Partial[B, C]): Partial[A, C] =
(x: A) =>
for {
y <- f1(x)
z <- f2(y)
} yield z
def identity(f: Partial[A, B]): Partial[A, B] = x => f(x)
}
val safeRecip: Partial[Double, Double] = {
case 0d => None
case x => Some(1d / x)
}
val safeRoot: …Run Code Online (Sandbox Code Playgroud) 我正在从“学习Haskell为伟大!”一书中学习单子。由Miran Lipovaca撰写。我试图理解单子的结合律。本质上,法律规定,当您使用拥有一元函数应用程序链时>>=,如何嵌套它们无关紧要。
以下代码使人们能够将type函数的结果传递给type a -> m b函数b -> m c:
(<=<) :: (Monad m) => (b -> m c) -> (a -> m b) -> (a -> m c)
f <=< g = (\x -> g x >>= f)
Run Code Online (Sandbox Code Playgroud)
但是,对于以下示例:
ghci> let f x = [x, -x]
ghci> let g x = [x*3, x*2]
ghci> let h = f <=< g
ghci> h 3
[9, -9, 6, -6]
Run Code Online (Sandbox Code Playgroud)
是f x和g x两个功能?看来它们是具有不同x值而不是函数的列表。该行在 …