我如何在 kind 的 monads 中重复 monadic 指令?
how can I repeat monadic instructions inside kind's monads?
我知道我可以 运行 monadic instructions inside monads in Kind language, like this:
Test: _
IO {
IO.print(Nat.show(2))
IO.print(Nat.show(3))
IO.print(Nat.show(4))
}
output:
2
3
4
但是是否可以重复 运行 monadic 指令,如下所示?
Test: _
a = [2,1,3,4,5]
IO {
for num in a:
IO.print(Nat.show(num))
}
如果可以的话,我该如何正确操作?
Monad 通常仅由两个运算符表示:
return :: a -> m(a) // that encapulapse the value inside a effectful monad
>>= :: m a -> (a -> m b) -> m b
// the monadic laws are omitted
注意,绑定运算符是自然递归的,一旦它可以组合两个 monad 甚至丢弃一个的值,return 可以被认为是“基本情况”。
m >>= (\a -> ... >>= (\b -> ~ i have a and b, compose or discard? ~) >>= fixpoint)
你只需要生成那个序列,这非常简单。例如,在 Kind 中,我们将 monad 表示为一对,它接受一个类型对类型的值并封装一个多态类型。
type Monad <M: Type -> Type> {
new(
bind: <A: Type, B: Type> M<A> -> (A -> M<B>) -> M<B>
pure: <A: Type> A -> M<A>
)
}
在你的例子中,我们只需要触发效果并丢弃值,递归定义就足够了:
action (x : List<String>): IO(Unit)
case x {
nil : IO.end!(Unit.new) // base case but we are not worried about values here, just the effects
cons : IO {
IO.print(x.head) // print and discard the value
action(x.tail) // fixpoint
}
}
test : IO(Unit)
IO {
let ls = ["2", "1", "3", "4", "5"]
action(ls)
}
如您所知,IO 将通过一系列绑定进行脱糖!
通常在列表的情况下,它可以像 haskell 库的 mapM 函数一样被概括:
Monadic.forM(A : Type -> Type, B : Type,
C : Type, m : Monad<A>, b : A(C), f : B -> A(C), x : List<A(B)>): A(C)
case x {
nil : b
cons :
open m
let k = App.Kaelin.App.mapM!!!(m, b, f, x.tail)
let ac = m.bind!!(x.head, f)
m.bind!!(ac, (c) k) // the >> operator
}
它自然会丢弃值,最后我们可以做到:
action2 (ls : List<String>): IO(Unit)
let ls = [IO.end!(2), IO.end!(1), IO.end!(3), IO.end!(4), IO.end!(5)]
Monadic.forM!!!(IO.monad, IO.end!(Unit.new), (b) IO.print(Nat.show(b)), ls)
所以,action2 执行相同的操作,但在一行中!。
当你需要组合你可以表示为 monadic fold 的值时:
Monadic.foldM(A : Type -> Type, B : Type,
C : Type, m : Monad<A>, b : A(C), f : B -> C -> A(C), x : List<A(B)>): A(C)
case x {
nil : b
cons :
open m
let k = Monadic.foldM!!!(m, b, f, x.tail)
m.bind!!(x.head, (b) m.bind!!(k, (c) f(b, c)))
}
例如,假设您想在循环中对要求用户的一系列数字求和,您只需调用 foldM 并使用一个简单的函数组合即可:
Monad.action3 : IO(Nat)
let ls = [IO.get_line, IO.get_line, IO.get_line]
Monadic.foldM!!!(IO.monad, IO.end!(0),
(b, c) IO {
IO.end!(Nat.add(Nat.read(b), c))
},
ls)
test : IO(Unit)
IO {
get total = action3
IO.print(Nat.show(total))
}
目前,Kind 不支持类型类,因此它使事情变得更加冗长,但我认为将来可以考虑对 forM 循环语法的新支持。我们希望如此:)
我知道我可以 运行 monadic instructions inside monads in Kind language, like this:
Test: _
IO {
IO.print(Nat.show(2))
IO.print(Nat.show(3))
IO.print(Nat.show(4))
}
output:
2
3
4
但是是否可以重复 运行 monadic 指令,如下所示?
Test: _
a = [2,1,3,4,5]
IO {
for num in a:
IO.print(Nat.show(num))
}
如果可以的话,我该如何正确操作?
Monad 通常仅由两个运算符表示:
return :: a -> m(a) // that encapulapse the value inside a effectful monad
>>= :: m a -> (a -> m b) -> m b
// the monadic laws are omitted
注意,绑定运算符是自然递归的,一旦它可以组合两个 monad 甚至丢弃一个的值,return 可以被认为是“基本情况”。
m >>= (\a -> ... >>= (\b -> ~ i have a and b, compose or discard? ~) >>= fixpoint)
你只需要生成那个序列,这非常简单。例如,在 Kind 中,我们将 monad 表示为一对,它接受一个类型对类型的值并封装一个多态类型。
type Monad <M: Type -> Type> {
new(
bind: <A: Type, B: Type> M<A> -> (A -> M<B>) -> M<B>
pure: <A: Type> A -> M<A>
)
}
在你的例子中,我们只需要触发效果并丢弃值,递归定义就足够了:
action (x : List<String>): IO(Unit)
case x {
nil : IO.end!(Unit.new) // base case but we are not worried about values here, just the effects
cons : IO {
IO.print(x.head) // print and discard the value
action(x.tail) // fixpoint
}
}
test : IO(Unit)
IO {
let ls = ["2", "1", "3", "4", "5"]
action(ls)
}
如您所知,IO 将通过一系列绑定进行脱糖! 通常在列表的情况下,它可以像 haskell 库的 mapM 函数一样被概括:
Monadic.forM(A : Type -> Type, B : Type,
C : Type, m : Monad<A>, b : A(C), f : B -> A(C), x : List<A(B)>): A(C)
case x {
nil : b
cons :
open m
let k = App.Kaelin.App.mapM!!!(m, b, f, x.tail)
let ac = m.bind!!(x.head, f)
m.bind!!(ac, (c) k) // the >> operator
}
它自然会丢弃值,最后我们可以做到:
action2 (ls : List<String>): IO(Unit)
let ls = [IO.end!(2), IO.end!(1), IO.end!(3), IO.end!(4), IO.end!(5)]
Monadic.forM!!!(IO.monad, IO.end!(Unit.new), (b) IO.print(Nat.show(b)), ls)
所以,action2 执行相同的操作,但在一行中!。 当你需要组合你可以表示为 monadic fold 的值时:
Monadic.foldM(A : Type -> Type, B : Type,
C : Type, m : Monad<A>, b : A(C), f : B -> C -> A(C), x : List<A(B)>): A(C)
case x {
nil : b
cons :
open m
let k = Monadic.foldM!!!(m, b, f, x.tail)
m.bind!!(x.head, (b) m.bind!!(k, (c) f(b, c)))
}
例如,假设您想在循环中对要求用户的一系列数字求和,您只需调用 foldM 并使用一个简单的函数组合即可:
Monad.action3 : IO(Nat)
let ls = [IO.get_line, IO.get_line, IO.get_line]
Monadic.foldM!!!(IO.monad, IO.end!(0),
(b, c) IO {
IO.end!(Nat.add(Nat.read(b), c))
},
ls)
test : IO(Unit)
IO {
get total = action3
IO.print(Nat.show(total))
}
目前,Kind 不支持类型类,因此它使事情变得更加冗长,但我认为将来可以考虑对 forM 循环语法的新支持。我们希望如此:)