Haskell / XMonad:表达式的自然类型是什么?在一系列操作之后必须完成某些事情? [英] Haskell/XMonad: What is the natural type for expressing that something must be done after a sequence of actions?
问题描述
我有一系列 X()
动作,在这些动作中可能会抓住某些按钮(并且之后不会释放)。为了防止按钮被抓住,我因此必须在最后取消所有按钮,例如:
action1> ;> action2>> action3>> ungrabAllButtons
我希望将此需求编码为一个类型,以便 action1
, action2
, action3
只有在按钮之后未被取消时才能使用。也就是说,即使 action1
, action2
,确实是 X()
操作,我希望它们不能用于此类,除非它们被包装在如下内容中(借用关键字借用Python的):
withGrabbedButtons :: ??? - > X()
withGrabbedButtons action =
action>> ungrabAllButtons
- 正确; complete_action不会让鼠标抓住
complete_action :: X()
complete_action = withGrabbedButtons(action1>> action2>> action3)
- 类型错误!
erroneous_single_action :: X()
erroneous_single_action = action1
- 类型错误!
erroneous_action :: X()
erroneous_action = action1>> action2>> action3
这样人们不会意外地使用 action1
, action2
, action3
作为 X()
行动,同时忘记随后取消按钮。
Haskell的类型系统有可能吗?事先感谢。
您需要做的是为 X
使用 GeneralizedNewtypeDiving
来获得一个免费的 Monad
实例:
{ - #LANGUAGE GeneralizedNewtypeDivingiving# - }
newtype XNeedsCleanup a = FromX {toX :: X a}
派生(Functor,Applicative,Monad )
因为 XNeedsCleanup
是monad,所以可以将多个 XNeedsCleanup
绑定在一起,如 action1>>所示。 action2>> action3
例子;这将在 FromX
包装器中将所有包装的 X
动作绑定在一起。但是,您将无法将产生的操作与 X
操作绑定;这就是 withGrabbedButtons
的来源:
withGrabbedButtons :: XNeedsCleanup() - > X()
withGrabbedButtons action = toX action>> ungrabAllButtons
如果您不导出 toX
unwrapper,您的客户无法通过 withGrabbedButtons
使用 XNeedsCleanup
值。但是如果他们有能力使用任意 X
动作,那么他们可以导入任何你用来定义你的各种动作的东西,并且可以将它们重新实现为原始 X
操作。所以只是为了明确:这不是安全导向的安全,只是防止人们意外地忘记清理。
I have a sequence of X()
actions during which certain buttons might be grabbed (and not released afterwards). In order to prevent buttons from ending up grabbed, I therefore have to ungrab every button at the end, for example:
action1 >> action2 >> action3 >> ungrabAllButtons
I wish to encode this requirement as a type, so that action1
, action2
, action3
can only be used if the buttons are ungrabbed afterwards. That is, even though action1
, action2
, are really X()
actions, I would like them not to be usable as such unless they are wrapped in something like the following (borrowing Python's with
keyword):
withGrabbedButtons :: ??? -> X()
withGrabbedButtons action =
action >> ungrabAllButtons
-- correct ; complete_action does not leave the mouse grabbed
complete_action :: X()
complete_action = withGrabbedButtons (action1 >> action2 >> action3)
-- type error!
erroneous_single_action :: X()
erroneous_single_action = action1
-- type error!
erroneous_action :: X()
erroneous_action = action1 >> action2 >> action3
This is so that people do not accidentally use action1
, action2
, action3
as X()
actions, while forgetting to ungrab the buttons afterwards.
Is this possible with Haskell's type system? Thanks beforehand.
What you will want to do is make a newtype wrapper for X
, using GeneralizedNewtypeDeriving
to get a free Monad
instance:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype XNeedsCleanup a = FromX { toX :: X a }
deriving (Functor, Applicative, Monad)
Because XNeedsCleanup
is a monad, you can bind multiple XNeedsCleanup
together, as in your action1 >> action2 >> action3
example; this will bind all of their wrapped X
actions together inside the FromX
wrapper. But you won't be able to bind the resulting action with an X
action; that's where your withGrabbedButtons
comes in:
withGrabbedButtons :: XNeedsCleanup () -> X ()
withGrabbedButtons action = toX action >> ungrabAllButtons
If you don't export the toX
unwrapper, your clients won't be able to use an XNeedsCleanup
value without going through withGrabbedButtons
. But if they have the ability to use arbitrary X
actions, then presumably they can import whatever you use to define your various actions and could reimplement them as "raw" X
actions. So just to be explicit: this isn't security-oriented safety, just preventing people from accidentally forgetting the cleanup.
这篇关于Haskell / XMonad:表达式的自然类型是什么?在一系列操作之后必须完成某些事情?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!