好吧,除非完美的世界你指的是心灵感应计算机(哎呀!),那么你需要某种方式来处理用户我/O - 我假设像 orthogonal persistence 这样的东西已经包含了更无聊的 file I/O...
让我们从输入开始...因为它已经有了一个解决方案。来自 Conal Elliott 和 Paul Hudak 的开创性论文的第 4 页(共 11 页)Functional Reactive Animation:
磅; rbp : 时间 → 事件 事件 ( )
在 Haskell 中,它看起来像:
-- read left and right mouse button-press events
lbp, rbp :: Time -> Event (Event ())
所以对于键盘输入:
kbd :: Time -> Event Char.
可以以类似的方式处理其他输入。
那么……输出呢?实际的词没有出现在论文的任何地方(“I/O”也没有出现)——我们必须自己弄清楚这个。但这一次,是我们的 Haskell 翻译:
lbp, rbp :: Time -> Event (Event ())
提供提示 - Event () - 单元事件。这可以作为发送 Char 关闭的结果,以显示在屏幕上的某个位置:
viewChar :: Char -> Time -> Event ()
同样,可以使用类似的技术处理其他输出。
...那是什么 - 它不是外延的?
因为viewChar 是...什么 - 不纯?
如果是这样,那意味着lbp 和rbp 也是不纯的——你确定吗?
好吧...让我们有一个类型来接收一系列鼠标按钮按下或其他事件:
type Intake a = [a]
lpb, rbp :: Intake (Event (Event ())
那个更好吗?好的!嗯,有点——
如果鼠标被拔掉会发生什么?那
可以将程序的一部分放入等待输入的旋转中(并且使用 [] 将永久结束该系列 - 不再按下按钮!)。
我们需要更改Intake:
data Intake a = None (Intake a) | Next a (Intake a)
现在拔掉鼠标会导致None …
出现,程序可以检测到并做出相应的反应,例如产生它的操作系统线程,
暂停自身等。
那么,输出呢?好吧,输出设备通常也可以拔掉。来自Intake的提示:
data Outlet a = Wait (Outlet a) | Went (… (Outlet a) …)
类似于拔掉输入设备——遇到
Wait …,程序可以暂停传输。
那么Went 的类型应该是什么?好吧,Outlet 逐渐接受值以允许 Wait … 在需要时出现 - 每个值的接受应该向我们展示 Output 的其余部分。因此:
data Outlet a = Wait (Outlet a) | Went (a -> Outlet a)
完全做到这一点:
data Intake a = None (Intake a) | Next a (Intake a)
lbp, rbp :: Intake (Event (Event ())
data Outlet a = Wait (Outlet a) | Went (a -> Outlet a)
viewChar :: Outlet Char
那么这一切都有效吗?如果您不确定,请参阅 Magnus Carlsson 和 Thomas Hallgren 的 Fudgets - Purely Functional Processes with applications to Graphical User Interfaces 的第 20.4.2 节(第 86 页,共 263 页) - 如果 Intake 和 Outlet 看起来很可疑,那么在纸...