Michael,

I think what you're trying to do is perfectly doable in Haskell and I think
the right tool for it is arrows, as Tomasz Zielonka mentioned before. I
suggest you take a look at the following paper which uses arrows to enforce
security levels in the code:
http://www.cis.upenn.edu/~stevez/papers/abstracts.html#LZ06a

Cheers,

Josef

On 6/25/07, Michael T. Richter <[EMAIL PROTECTED]> wrote:

 On Mon, 2007-25-06 at 12:19 +0300, Benja Fallenstein wrote:

2007/6/25, Michael T. Richter <[EMAIL PROTECTED]>:

 OK, just to prevent this getting side-tracked: I'm absolutely
uninterested in the results of performActionA before determining if
performActionB is permitted/possible/whatever.  Think more in terms of
security permissions or resource availability/claiming than in terms of
chaining results.  I want to know before I begin to collect the results of
performAction* that I will actually stand a chance at getting results at
all.


Uh, the posts you quote were precisely about how to do that. No
side-tracking going on. :-)


It looked to me like there were people arguing about whether the "x"
returned from one action was going to be used in the next action.

Let me try and rephrase the question.  [image: :)]

A conventional approach to what I'm doing would be something like this (in
bad pseudocode):

doStuff():
    if checkPossible([opA, opB, opC]):
        A
        B
        C
    else:
        exception "Preconditions not met"

My objection to this is its error-prone scaffolding:

   1. There's no enforced link between the checking operations and the
   actual operations.  By mistake or by deliberate action it is possible to put
   operations in the main body which have not been checked by the guards.
   2. As code evolves and changes, it is very easy to have the check
   diverge from the contents of the body as well.


Now if the actions were trivial or easily reversible, an alternative model
is something like this (in bad pseudocode) where it's assumed that each
operation checks for its privileges/capabilities/whatever as part of its
operation:

doStuff2():
    A
    try:
        B
        try:
            C
        catch:
            undoB
            throw
    catch:
        undoA

This looks to me like Don Stuart's "executable semi-colons" and could be
coded as a pretty conventional monad (unless my eyes are deceiving me).  But
if doing A, say, involved expensive operations (think: generating an RSA key
or making a database connection on a heavily-loaded server) or if doing B
involved modifying some external state that is difficult to undo this is a
less-than-ideal model.  Let's say that C fails for whatever reason
(insufficient privileges, the database server is dead, the phase of the moon
is wrong for the species of chicken sacrificed at the keyboard -- anything),
then we've got time wasted in A and B has just changed something we can't
easily unchange.

So I'd like some way of getting the automated check of
permission/capability/availability/whatever done before performing the
actual actions.

Now in a language where functions are identifiable types, a solution could
look like this (among a myriad of other possible solutions):

check(Operation):
    case Operation of:
        A:
            return checkConditionA
        B:
            return checkConditionB
        C:
            return checkConditionC

runStuff(actions):
    for each action in actions:
        if not check(action.left):
            throw CheckFailure
    for each action in actions:
        action.left(action.right)

doStuff3():
    actions=[(A, a_args), (B, b_args), (C, c_args)]
    try:
        runStuff(actions)
    catch CheckFailure:
        actions=nil

The check() function called here can use the identity of the action
provided plus any information provided externally (network connections open,
permissions available, etc.) to pass/fail the
capabilities/resources/whatever and the action's execution is deferred until
the check has passed.  The action's check *AND* its execution is unavailable
to the programmer so there's less room for fraud and oversight and all the
other things which make programs buggy and unreliable and such joys to work
with both as a programmer and as a user.  In fact with languages as
malleable as Ruby (or possibly even Python) some of the ugly scaffolding
above could be made to vanish behind the scenes leaving pretty clean code
behind.  (Uglier languages like C/C++, of course, would leave all the
scaffolding lying around, but it would still be doable.)

But of course this can't be done in Haskell this way because functions
aren't items in Haskell.  There is no function equality check.  My check()
function can't look like:

check :: (a->b)
check A = ...
check B = ...
check C = ...
check _ = error "no such function"

This leaves me in a position I can't think myself out of (hence the cry
for help).  I'd like it to be possible to have a do block with as little
visible scaffolding as possible (ideally *none*) where I can do the
equivalent of doStuff3() and runStuff() from the above pseudocode.

Now here's the tricky part....

I'd ideally like to be able to do this so that it would be possible to
start with the doStuff2 implementation behind the scenes (check as you go)
and then, by changing the scaffolding behind the scenes, do the doStuff3()
implementation *without touching a line of client code*.  In effect I'd
like to be able to change computing strategies on the fly without the client
code having to be modified.  If we look at my doStuff3() as an example, for
instance, I could switch it over from a pre-check to a check-as-you-go
system pretty easily by modifying runStuff() and the check().  runStuff()
would be modified to interleave the check with the call and check would be
modified to return an undo operation kept in an accumulator by runStuff() or
nil.  If nil is returned, the list of undo operations maintained by runStuff
would get executed and the failure signalled.

Does this make more sense now?  And can it be done somehow in Haskell?

  --
*Michael T. Richter* <[EMAIL PROTECTED]> (*GoogleTalk:*
[EMAIL PROTECTED])
*Those who have learned from history are bound to helplessly watch it
repeat itself. (Albert Y. C. Lai)*

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe



<<inline: smiley-3.png>>

_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to