做一些家庭项目,我遇到了一个感兴趣的效果,现在,对我来说似乎很明显,但我仍然没有办法摆脱它.这是要点(我使用ScalaZ,但在haskell中可能会有相同的结果):
def askAndReadResponse(question: String): IO[String] = {
putStrLn(question) >> readLn
}
def core: IO[String] = {
val answer: IO[String] = askAndReadResponse("enter something")
val cond: IO[Boolean] = answer map {_.length > 2}
IO.ioMonad.ifM(cond, answer, core)
}
Run Code Online (Sandbox Code Playgroud)
当我试图从中获取输入时core,askAndReadResponse评估两次 - 一次用于评估条件,然后用于ifM(因此我有消息,readLn然后再需要一次).我需要什么 - 只是验证的值(例如,稍后打印)
有没有优雅的方法来做到这一点,特别是 - 进一步传递IO的结果,没有先前的IO动作,即避免执行 askAndReadResponse两次?
我们可以将monad描述为计算上下文,monad实现完全保留了该上下文的含义.例如Option - 上下文含义是值可能存在.给定Option数据类型,唯一有意义的实现是pure = some, flatMap f = {none => none; some x => f x }
正如我对monad的理解,通过遵循类型签名 - 对于任何monad只有一个合理的实现.换句话说,如果要为值/计算添加一些有意义的上下文,则只有一种方法可以为任何特定的monad执行此操作.
另一方面,当涉及到comonad时,它突然开始感觉完全奇怪,就像有很多方法来实现给定类型的comonad,你甚至可能为每个实现赋予一定的意义.
NEL考虑一下copure = head. cojoin通过实现tails,完全满足类型.如果我们实现了cojoin通过permutations或fa map (_ => fa) map f将无法满足comonad法律.
但循环实施是有效的:
override def cobind[A, B](fa: NonEmptyList[A])(f: (NonEmptyList[A]) => B): NonEmptyList[B] = {
val n: NonEmptyList[NonEmptyList[A]] = fa.map(_ => fa).zipWithIndex.map { case (li , i ) =>
val(h: List[A], t: List[A]) = li.list.splitAt(i)
val …Run Code Online (Sandbox Code Playgroud) 我学习不成形,目前我试图创建一个具有以下功能:给定一个类型的HList它返回HList的NoneS,与Option相应的给定类型的HList类型.
例如:
create[String :: Int :: HNil] // returns None[String] :: None[Int] :: HNil
Run Code Online (Sandbox Code Playgroud)
所以逻辑如下:
def create[A <: HList] {
type HT = ??? //somehow getting Head type
type TT = ??? //somehow getting Tail type
// if HT is HNil HNil else Option.empty[HT] :: create[TT]
}
Run Code Online (Sandbox Code Playgroud)
看起来像HT和TT可以提供IsHCons
def createHList[L <: HList](implicit ihc: IsHCons[L]): HList = {
type HT = ihc.H
type TT = ihc.T …Run Code Online (Sandbox Code Playgroud)