Python from Wise Guy's Viewpoint

Brian McNamara! gt5163b at prism.gatech.edu
Sat Oct 25 15:11:28 EDT 2003


prunesquallor at comcast.net once said:
>(defun lookup (item table if-found if-missing)
>  (cond ((null table) (funcall if-missing))
>        ((eq item (entry-key (first-entry table)))
>         (funcall if-found (entry-value (first-entry table))))
>        (t (lookup item (remaining-entries table)
>                   if-found
>                   if-missing))))
>
>(defun lookup-default (item local-table default-table if-found if-not-found)
>  (lookup item local-table 
>          if-found
>          (lambda () 
>            (lookup item default-table if-found if-not-found))))
>
>(defun transform-list (list local-table default-table if-ok if-fail)
>  (if (null list)
>      (funcall if-ok '())
>      (lookup-default (car list) local-table default-table
>        (lambda (result)
>          (transform-list (cdr list) local-table default-table
>            (lambda (remainder)
>              (funcall if-ok (cons result remainder)))
>            if-fail))
>        (lambda () (funcall if-fail (car list))))))
>
>I know that simple static type checkers will be lost with this.
>I do not know if the smarter ones will.

If I have read that correctly, it looks like it admits these Haskell
types:

   lookup :: 
      (Eq k)=> k -> Map k v -> (v -> a) -> a -> a
   lookupDefault :: 
      (Eq k)=> k -> Map k v -> Map k v -> (v -> a) -> a -> a
   transformList :: 
      (Eq k)=> k -> Map k v -> Map k v -> ([a] -> b) -> (k -> a) -> [b]

except that in transformList, types "a" and "[b]" must be the same, due
to the awkward[*] way the exception-handling works with if-fail.

[*] Awkward from the static-typing point-of-view, of course.  I think a 
Haskell programmer would rewrite transformList with this type instead:

      (Eq k)=> k -> Map k v -> Map k v -> ([a] -> b) -> (k -> c) 
               -> Either c b

using the "Either" type to handle the exceptional case.  The
implementation would then be just

   transformList l locTable defTable ifOk ifFail =
      if (null l) 
         then Right (ifOk l)
         else lookupDefault (head l) locTable defTable
            (\r -> transformList (tail l) locTable defTable 
               (\remain -> ifOk (cons r remain)) ifFail)
            (Left (ifFail (head l)))

Thus, if one of the lookup fails, we'll get back a "Left" Either,
describing where the problematic input was, whereas if they all succeed,
we'll get back a "Right" Either, with the expected kind of result.

Actually, rewriting all of these functions using the Error monad would
make it all more elegant.

(Of course, the usual "I'm doing this all by hand" disclaimer applies.
Any type errors are my own.)

-- 
 Brian M. McNamara   lorgon at acm.org  :  I am a parsing fool!
   ** Reduce - Reuse - Recycle **    :  (Where's my medication? ;) )




More information about the Python-list mailing list