我有一系列X()
个动作,在此期间可能会抓取某些按钮(之后不会释放)。为了防止按钮最终被抓住,我因此必须在最后取消每个按钮,例如:
action1 >> action2 >> action3 >> ungrabAllButtons
我希望将此要求编码为一种类型,以便action1
,action2
,action3
只能在以后按钮未被删除时使用。也就是说,即使action1
,action2
实际上是X()
个动作,我希望它们不会被这样使用,除非它们包含在以下内容中(借用Python&#39) ; s with
关键字):
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
这样人们就不会意外地使用action1
,action2
,action3
作为X()
操作,而忘记在之后取消按钮。
这是否适用于Haskell的类型系统?先谢谢。
答案 0 :(得分:1)
您要做的是为X
创建一个newtype包装器,使用GeneralizedNewtypeDeriving
获取免费Monad
实例:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype XNeedsCleanup a = FromX { toX :: X a }
deriving (Functor, Applicative, Monad)
由于XNeedsCleanup
是一个monad,您可以将多个XNeedsCleanup
绑定在一起,就像在action1 >> action2 >> action3
示例中一样;这将在X
包装器中将所有包装的FromX
操作绑定在一起。但是,您将无法使用X
操作绑定结果操作;那就是你withGrabbedButtons
进来的地方:
withGrabbedButtons :: XNeedsCleanup () -> X ()
withGrabbedButtons action = toX action >> ungrabAllButtons
如果您不导出toX
解包器,则客户将无法通过XNeedsCleanup
使用withGrabbedButtons
值。但如果他们有能力使用任意X
个动作,那么可能他们可以导入您用来定义各种动作的任何动作,并可以将它们重新实现为“原始”X
动作。所以要明确一点:这不是安全导向的安全,只是防止人们意外忘记清理。
答案 1 :(得分:0)
您可能想要创建自己的bracket版本。 Bracket在package fourfive;
import java.util.Random;
public class Computer extends Human {
protected static Random rand = new Random();
protected int maxGuess;
Computer(int playerNum) {
super(playerNum);
maxGuess = 1000;
}
Computer(int playerNum, int topNum){
super(playerNum);
maxGuess = topNum;
}
@Override
public void guess() {
int guess = rand.nextInt(maxGuess);
System.out.println("Bot " + playerNum + " turn *" + guess + "*");
guesses.push(guess);
}
public int getMaxGuess() {
return maxGuess;
}
public void setMaxGuess(int num) {
maxGuess = num;
}
}
monad中工作,但基于对源代码的快速浏览,我怀疑你可以创建自己的版本在IO
monad中运行。即使引发异常,Bracket也会确保发生任何终结(例如,取消所有按钮)。