如果你想附加两个类型为(a - > mb)的函数,这样你只能得到一个相同类型的函数来追加两个结果,你可以使用Kleisli来做到这一点:
instance (Monad m, Monoid b) => Monoid (Kleisli m a b) where
mempty = Kleisli (\_ -> return mempty)
mappend k1 k2 =
Kleisli g
where
g x = do
r1 <- runKleisli k1 x
r2 <- runKleisli k2 x
return (r1 <> r2)
Run Code Online (Sandbox Code Playgroud)
但是,目前没有定义这样的实例Control.Arrow.通常,在Haskell,我怀疑有一个很好的理由,但找不到哪一个.
这个问题是相当类似,这一个.但是,使用Monoid我没有看到定义实例的方法,例如:
instance (Monad m, Monoid b) => Monoid (a -> m b) where
[...]
Run Code Online (Sandbox Code Playgroud)
因为已经存在一个实例:
instance Monoid b => Monoid (a -> b) where
[...]
Run Code Online (Sandbox Code Playgroud) 阅读本文后,我理解>=>(Kleisli arrow)只是一个组合函数的高阶函数,它返回"monadic values".例如:
val f: A => M[B] = ... val g: B => M[C] = ... val h: A => M[C] = f >=> g // compose f and g with Kleisli arrow
它看起来像是一个简单的"简单"函数组合(即返回简单值的纯函数):
val f: A => B = ... val g: B => C = ... val h = f andThen g; // compose f and g
现在我猜这个"简单"的构图andThen符合某些规律
f andThen g == g和g andThen f …在斯卡拉兹
Kleisli[F, A, B]是一个包装A => F[B].ReaderT[F, A, B]- 读者monad变换器 - 只是别名Kleisli[F, A, B].Reader[A, B]monad是ReaderT身份monad 的专长Id:type Reader[A, B] = ReaderT[Id, A, B].难道仅仅是巧合还是有一些更深层次的原因Kleisli,ReaderT以及Reader是同构的Scalaz?
我想>=>在Scala中使用(Kleisli箭头).据我所知,它组成了返回monad的函数.现在我尝试如下:
scala> val f = {i:Int => Some(i + 1)}
f: Int => Some[Int] = <function1>
scala> val g = {i:Int => Some(i.toString)}
g: Int => Some[String] = <function1>
scala> val h = f >=> g
<console>:15: error: value >=> is not a member of Int => Some[Int]
val h = f >=> g
^
为什么不编译?如何撰写f和g搭配>=>?
在Haskell Control.Arrow文档中,它讨论了Kleisli箭头与monad的关系,但对我来说如何使用它并不明显.我有一个我认为适合箭头的功能,除了它涉及IO monad,所以我认为Kleisli箭头可能有帮助.
使用以下函数返回目录的原始和修改文件名对.
import System.Directory
import System.FilePath
datedFiles target = do
fns <- getDirectoryContents target
tms <- mapM (fmap show . getModificationTime) fns
return $
zip fns $
zipWith replaceBaseName fns $
zipWith (++) (map takeBaseName fns) tms
Run Code Online (Sandbox Code Playgroud)
如果我必须把它画出来,它将是这样的:

我认为它可以从Kleisli箭头的使用中受益,但我不知道如何.有人可以提供指导吗?
在scalaz中 Kleisli[M[_], A, B]是一个包装器A => M[B],它允许组合这些功能.举例来说,如果M[_]是我单子可以撰写Kleisli[M, A, B],并Kleisli[M, B, C]用>=>得到Kleisli[M, A, C].
简而言之,取决于Kleisli提供花式.这是对的吗 ?使用还有其他好处吗? andThensMKleisli
假设我有
type VS[A] = Validation[String, A]
val v: VS[Option[A]]
val f: A => VS[B]
Run Code Online (Sandbox Code Playgroud)
我想获得类型的结果,VS[Option[B]]但如果v是a Success(None),结果也应该是a Success(None).这是一个例子:
scala> val v: VS[Option[String]] = some("4.5").success
v: VS[Option[String]] = Success(Some(4.5))
scala> val f = (s : String) => (try { s.toInt.success } catch { case x => x.getMessage.fail }): VS[Int]
f: String => VS[Int] = <function1>
Run Code Online (Sandbox Code Playgroud)
然后:
scala> import Validation.Monad._
import Validation.Monad._
scala> (v map2 f map (_.sequence)).join
res4: scalaz.Validation[String,Option[Int]] = Failure(For input string: "4.5")
Run Code Online (Sandbox Code Playgroud)
成功案例是:
scala> …Run Code Online (Sandbox Code Playgroud) functional-programming scala monad-transformers scalaz kleisli
我遵循了功能和反应建模一书中的设计原则.
所以所有的服务方法都返回Kleisli.
问题是如何在这些服务上添加可更新缓存.
这是我目前的实现,有更好的方法(现有组合器,更多功能方法,......)?
import scala.concurrent.duration.Duration
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.{Await, Future}
import scalaz.Kleisli
trait Repository {
def all : Future[Seq[String]]
def replaceAll(l: Seq[String]) : Future[Unit]
}
trait Service {
def all = Kleisli[Future, Repository, Seq[String]] { _.all }
def replaceAll(l: Seq[String]) = Kleisli[Future, Repository, Unit] { _.replaceAll(l) }
}
trait CacheService extends Service {
var cache : Seq[String] = Seq.empty[String]
override def all = Kleisli[Future, Repository, Seq[String]] { repo: Repository =>
if …Run Code Online (Sandbox Code Playgroud) 我想知道是否有办法把List[Kleisli[Option, Int, Int]]到Kleisli[Option, Int, List[Int]].
特别是我有像这样形成的kleisli列表:
def k(a: String) = Kleisli[Option, Int, Int](m => Some(a.length * m))
val kList = List("hi", "hello").map(k)
Run Code Online (Sandbox Code Playgroud)
我所做的是以下内容
Kleisli[Option, Int, List[Int]](m => kList.map(_.run(m)).sequence)
Run Code Online (Sandbox Code Playgroud)
这是非常混乱,没有表现力,需要大量的手工工作.
有没有更好的办法?
编辑:p如果存在以下功能f,我们将调用纯箭头:p = arr f。
我试图更好地了解Haskell中的Arrows,我想弄清楚何时
f >>> (g &&& h) = (f >>> g) &&& (f >>> h)其中f,g,h是箭头。
显然,通常情况并非如此。在此特定示例中,副作用在右侧重复:
GHCi> c = Kleisli $ \x -> ("AB", x + 1)
GHCi> fst . runKleisli (c >>> c &&& c) $ 1
"ABABAB"
GHCi> fst . runKleisli ((c >>> c) &&& (c >>> c)) $ 1
"ABABABAB"
Run Code Online (Sandbox Code Playgroud)
显然,f >>> (g &&& h) = (f >>> g) &&& …
kleisli ×10
scala ×7
scalaz ×5
monads ×4
haskell ×3
arrows ×2
reader-monad ×2
monoids ×1
scala-cats ×1