Haskell 单子挑战——一个遗漏的概括

Haskell 单子挑战——一个遗漏的概括,haskell,functional-programming,monads,state-monad,Haskell,Functional Programming,Monads,State Monad,我正在经历 在这一部分,我至少应该有这个代码(我删除了与问题无关的部分),其中Gen看起来很像州单子 ——导入和其他隐藏前奏的东西 --例如,do符号在挑战的这个阶段不可用 类型Gen a=种子->(a,种子) genTwo::Gena->(a->Gen b)->Gen b genTwo g f s=let(a,s')=g s 在f中 mkGen::a->Gen a mkGen a s=(a,s) 一般b::(a->b->c)->a世代->b世代->c世代 --我已经按照如下方式实现了它,并且它

我正在经历

在这一部分,我至少应该有这个代码(我删除了与问题无关的部分),其中
Gen
看起来很像州单子

——导入和其他隐藏前奏的东西
--例如,do符号在挑战的这个阶段不可用
类型Gen a=种子->(a,种子)
genTwo::Gena->(a->Gen b)->Gen b
genTwo g f s=let(a,s')=g s
在f中
mkGen::a->Gen a
mkGen a s=(a,s)
一般b::(a->b->c)->a世代->b世代->c世代
--我已经按照如下方式实现了它,并且它是有效的
一般b f a b s=let(x,s')=a s
(y,s'')=b s'
in(f x y,s“”)
“分配”的文本如下:

[…]您可能没有在
genTwo
方面实现
generalB
。返回并查看您的
generalB2
实现,如果您没有用
genTwo
编写它,现在就这样做,并将其命名为
generalB2
。这样做应该可以消除生成器之间的状态线程

我不清楚该怎么解决这个问题,特别是考虑到上面的段落没有提到
mkGen
。假设我能够将
f
应用到
a
b
的内部,我仍然会得到
c
类型的东西,我必须把它塞进
Gen
,如果没有
mkGen
或者没有明确使用
(,)
,我看不出我怎么能做到这一点(正如我在上述实施中所做的那样)

即使假设文本暗示我应该使用
mkGen
,我应该如何着手摆脱状态线程

经过一些编辑,我终于想出了这个

generalB2'fab=gentwoa(gentwob.(mkGen.).f)
但我几乎不相信这是预期的解决方案,因为在我看来,它远没有可读性。而且,到目前为止,在挑战中,获得这种形式比任何其他形式都要困难一些,但它毕竟只是机械的,所以我相信,从理解单子的角度来看,它并没有真正造成困难,所以我真的认为我在这里拐错了弯,我需要帮助


我想知道这些挑战的作者是否在StAdvExcel上挂起。

< P>您的解决方案可能接近于预期的解决方案,尽管您可以通过ETA扩展它使其更可读。您甚至可以考虑使用<代码> Do/<代码>注释来编写它,但仍然使用<代码> GoTWOW/<代码>和<代码> MKGEN < /代码> .< 据我所知,
mkGen
是一个“伪装的”
返回
函数,
genTwo
同样是一个“伪装的”一元绑定(即
>=

generalB
(和
generalB2
)的类型相当于
liftM2
,它:

liftM2::(Monad m)=>(a1->a2->r)->ma1->ma2->mr

liftM2 f m1 m2=do{x1=
(您看不到,因为它使用的是
do
语法)

< p>您的解决方案可能接近于预期的解决方案,尽管您可以通过ETA扩展它使其更可读。您甚至可以考虑使用<代码> do/<代码>注释来编写它,但仍然使用<代码> GoTWOW/<代码>和<代码> MKGEN < /代码> .< 据我所知,
mkGen
是一个“伪装的”
返回
函数,
genTwo
同样是一个“伪装的”一元绑定(即
>=

generalB
(和
generalB2
)的类型相当于
liftM2
,它:

liftM2::(Monad m)=>(a1->a2->r)->ma1->ma2->mr

liftM2 f m1 m2=do{x1=
(您看不到,因为它使用的是
do
语法)。

您可以将
a`genTwo`(\x->…
读作“滚动模具
a
一次,并让
x
作为其结果”。在下面,状态自动线程化,使代码更可读,更不容易出错(当你在线程中循环状态时,很容易错误地恢复到旧状态)。最后,你需要你所说的
mkGen
(或者你需要显式地执行线程状态)。@chi,我试着通过
a`genTwo`(\x->…
),但没走多远;我想我在最后迷路了[…]我相信您需要显式地执行线程状态。具体来说,我编写了一个类型检查函数,
generalb2fab=a`genTwo`(\a'->b`genTwo`(\b'->mkGen undefined))
,但是我不知道在占位符上放什么。你能给我一个解释这个问题的答案吗?哦,我想我明白了。最后一个lambda应该是
\b'->mkGen(fa'b')
。事实上,在一般的单子中我们会使用
一般的b2 fab=a>=(\a'->b>=(\b'->返回(fa'b'))
这是已知的
liftM2
。这里我们使用了“伪装”的定义,但代码的形状是相同的。是的,我对通信很清楚,并且通过网站上的文本非常明确地提出了建议。我想问题是我仍然很难对状态单子进行推理(尽管到目前为止从未看过解决方案),就像我必须通过状态和值的“通量”来尝试理解整个画面一样。如中所示,我必须看到管道,这有点困难。请随意添加答案,我会接受它。您可以阅读
a`genTwo`(\x->…
As“滚动骰子
a
一次,然后让
x
成为它的结果”。在下面,状态是自动线程化的,这使得代码更可读,更不容易出错(当您遍历状态时,很容易错误地恢复到旧状态)。最后,您需要如您所述的
mkGen
(或者您需要显式地执行线程状态)。@chi,我试图通过
a`genTwo`(\x->…
),但没有走多远;我想我在最后迷路了[…]您
liftM2  :: (Monad m) => (a1 -> a2 -> r) -> m a1 -> m a2 -> m r
liftM2 f m1 m2 = do { x1 <- m1; x2 <- m2; return (f x1 x2) }