[Haskell-cafe] Re: Practical Haskell question.
apfelmus
apfelmus at quantentunnel.de
Mon Jun 25 05:36:16 EDT 2007
Benja Fallenstein wrote:
> Hi Peter,
>
> 2007/6/25, peterv <bf3 at telenet.be>:
>> I'm baffled. So using the Arrow abstraction (which I don't know yet) would
>> solve this problem? How can (perfectActionB x) be checked with without
>> ever executing performActionA which evaluates to x? This can only be done
>> when x is a constant expression no?
>
> Arrows separate the action -- 'performActionB' -- from the argument --
> 'x', so you can look at the action before you have to compute the
> argument to it. Of course, this means that you can no longer compute
> the action from the argument -- that is, 'if x then performActionB
> else performActionC' is something you can't directly do; you have to
> use a choice primitive instead, which explicitly says "use one of
> these two arrows depending on what value this argument is," which then
> lets the library check these two arrows before actually applying them
> to an argument.
Well, arrows can't solve the problem as well iff performActionB may be
permissible _depending_ on x, i.e.
performActionB x = if x then pickFlowers else eraseHardDrive
There's no way to check whether performActionB is permissible for a
given run without executing performActionA for the permissibility of B
depends on the output of A.
But I think that Michael had conditions in mind that can be checked
before executing any of the actions. Of course, the simplest way is to
check manually:
do
if i'mRoot
then do
x <- performActionA
y <- performActionB
z <- performActionC
return $ calculateStuff x y z
else
cry "gimme root"
but you could still write performActionA somewhere without having
checked/established root permission. This can be solved by using a
custom monad
newtype Sudo a = Sudo { act :: IO a }
deriving (Functor,Monad,MonadIO)
which has the following operations
performActionA :: Sudo Int
performActionB :: Sudo String
etc.
and that can only be run with
sudo :: Sudo a -> IO (Either String a)
sudo m = do
b <- makeMeRoot
if b
then liftM Right $ act m
else return $ Left "Could not become Root"
Putting Sudo into a module and making it abstract ensures that you can't
break the invariant that stuff of type "Sudo a" will either be run as
root or not at all.
Regards,
apfelmus
More information about the Haskell-Cafe
mailing list