嗨,我正在尝试实现穷人的并发Monad.这是我的代码:
import Control.Monad
data Concurrent a = Concurrent ((a -> Action) -> Action)
data Action
= Atom (IO Action)
| Fork Action Action
| Stop
instance Monad Concurrent where
(Concurrent ma) >>= f = Concurrent (\x -> ma(\y -> "Something return a Action"))
return x = Concurrent (\c -> c x)
Run Code Online (Sandbox Code Playgroud)
这是我的分析:
x有类型b,y有类型a,f有类型(a -> ((b ->Action) -> Action)).为了弄清楚"Something return a Action",我首先计算(f y),返回一种类型((b ->Action) -> Action).然后,如何使用它x来生成一个Action?
Ste*_*ans 21
您正在寻找的定义类似于
Concurrent h >>= k = Concurrent (\f -> h (\x -> runConcurrent (k x) f))
Run Code Online (Sandbox Code Playgroud)
我们是怎么到达那里的?与往常一样,我们让类型完成工作.:)
我们先介绍一个辅助函数:
runConcurrent :: Concurrent b -> (b -> Action) -> Action
runConcurrent (Concurrent h) = h
Run Code Online (Sandbox Code Playgroud)
如果你从定义的左侧开始
Concurrent h >>= k = ...
Run Code Online (Sandbox Code Playgroud)
用h :: (a -> Action) -> Action和k :: a -> Concurrent b,然后你的目标是...用类型的表达式替换Concurrent b,不是吗?
我们如何构建一个类型的值Concurrent b?一种方法是应用我们的函数k,但这不起作用,因为我们没有合适的类型值a作为参数.所以,几乎我们所能做的唯一的事情是应用数据的构造Concurrent是类型((b -> Action) -> Action) -> Concurrent b.
这给了:
Concurrent h >>= k = Concurrent ...
Run Code Online (Sandbox Code Playgroud)
现在我们必须找到一个类型的表达式(b -> Action) -> Action作为参数供给Concurrent.我们知道函数类型的表达式总是可以通过lambda-abstraction构造:
Concurrent h >>= k = Concurrent (\f -> ...)
Run Code Online (Sandbox Code Playgroud)
这使我们f :: b -> Action有义务...用表达式替换Action.Action直接使用其中一个-constructors当然会作弊;).为了保证通用性(>>=)(更准确地说,确保我们最终遵守monad法则),我们将其Action视为抽象数据类型.然后,生成Action-value 的唯一方法是应用函数h:
Concurrent h >>= k = Concurrent (\f -> h ...)
Run Code Online (Sandbox Code Playgroud)
因此,接下来我们需要提供h类型的参数a -> Action.这又是一个函数类型,所以我们抛出另一个lambda:
Concurrent h >>= k = Concurrent (\f -> h (\x -> ...))
Run Code Online (Sandbox Code Playgroud)
因此,我们已经x :: a并且需要构建一个类型的主体Action.我们可以用类型的值做什么a?我们可以将它提供给该功能k.这给了我们一个类型的值Concurrent b,然后我们可以传递给我们的辅助函数runConcurrent:
Concurrent h >>= k = Concurrent (\f -> h (\x -> runConcurrent (k x) ...))
Run Code Online (Sandbox Code Playgroud)
这给了我们一个类型的函数,(b -> Action) -> Action并提供f作为参数的技巧:
Concurrent h >>= k = Concurrent (\f -> h (\x -> runConcurrent (k x) f))
Run Code Online (Sandbox Code Playgroud)