Posted by Tom Moertel
Sat, 27 Aug 2005 21:12:00 GMT
One of the projects I’m working on is a language to help researchers
manipulate genetics information. Despite all the well-publicized
advances in genetics, researchers still spend about a third of their
time writing shell, awk, and Perl scripts to manipulate their data.
If researchers can get some of this time back, they can use it to
think about more interesting problems, like curing cancer and stuff like that.
Read more...
Posted in functional programming, haskell
Tags haskell, parsec, parsing
7 comments
no trackbacks

Posted by Tom Moertel
Sat, 26 Mar 2005 00:06:00 GMT
In the last few days I have been learning
Ruby, something I have had on my
to-do list for a long time. Luckily, I now have a project for which Ruby on Rails
is perfect, and so now is the perfect time to get more into Ruby.
Naturally, I am making much use of the second edition of “The Pickaxe,” (pragmatic) Dave Thomas’s book
Programming Ruby (the first edition of which is available online). Overall, it is a great book: good organization, lively writing, and superb examples.
But I must say I have one source of frustration. I am a computer-language guy, and I frequently find myself thinking, that’s great, but what exactly does this mean? I’ll give you an example, which I found quite surprising.
Using the following Ruby code, you can create what is in effect your own while-loop construct:
def my_while(cond)
break unless cond
yield
retry
end
i = 0
my_while i < 10 do
print i
i += 1
end
At first, this blew my mind. Why? Because while reading the book, I
was building an understanding of the semantics of the Ruby language
in my head, and my understanding of what it means to call a function
(iterator) with a block was wrong. In my understanding, calling a
function results in evaluating its arguments in the caller’s
evaluation context, entering the evaluation context of the function,
binding the argument values, passing in the associated block, and then
evaluating the function body. When retry is called, I reasoned
mistakenly, the evaluation stops and begins anew at the beginning of
the function body, in this case, back at the break expression.
But, clearly, that cannot be what is happening. If it
were, the loop would never terminate. The condition
i < 10 would be evaluated only once – when the
my_while function was called – and thus true would be forever bound to cond
within the evaluation context of the function’s body.
At this point, I became curious. What’s really going
on with retry? To understand its relationship to function calls, I
started looking for the calling semantics of Ruby. (No luck finding
them, btw.) Are arguments passed as thunks that get reevaluated upon
each access? No, that seemed too wasteful and bizarre.
Pickaxe II said, “retry will reevaluate any arguments to the
iterator before restarting it.” Yes, clearly, that is what is
happening. But what is happening under the hood? What does that statement
really mean?
So, after thinking about it, I concluded that what is going on is
that a function call in Ruby works like this. Given a function f,
a block b, and arguments xs, the call f(xs){b}
means this:
- let k be the current continuation (i.e., just before the call)
- evaulate xs and bind the resulting values to f’s formal arguments
- bind b internally to the current block
- evaluate the body of f
Now, if inside of f’s body we encounter a retry, the evaluator
basically calls k (with a nil argument, I expect). This jumps
back to step 2, from which evaluation continues. Any side effects up
to this point are retained (so we could have previously incremented
i, for example), which is what eventually allows the code within the function
body to choose an execution path which does not contain a
retry expression, and thus avoid looping forever.
Just to make sure I really had the semantics down, I wrote an
evaluator for a mini-Ruby in Haskell. (I find that I understand something
better after I build it from the ground up.)
module MiniRuby where
import Control.Monad.Cont
import Control.Monad.Reader
import Control.Monad.State
import Data.List
import Data.Maybe
type Identifier = String
type Value = String
type Env = [(Identifier, Value)]
type RubyEvalCxt a = ContT a (ReaderT FcallCxt (State Env)) a
data FcallCxt = FC { retryCall :: Exp
, blockCont :: Value -> Exp }
type Exp = RubyEvalCxt Value
eval :: Env -> FcallCxt -> Exp -> Value
eval env fc =
(`evalState` env) . (`runReaderT` fc) . (`runContT` return)
evalTop = eval [] $
FC { retryCall = return "TOPLEVEL RETRY"
, blockCont = const $ return "TOPLEVEL BLOCK" }
fcall :: Exp -> [(Identifier, Exp)] -> Exp -> Exp
fcall fn args blk = callCC evalFn
where
evalFn fnCont = (`local` do { bindArgs; fn }) $ \fc ->
fc { retryCall = evalFn fnCont >>= fnCont
, blockCont = const blk }
bindArgs = mapM_ (uncurry (=:=)) args
yield_ = yield "YIELD"
yield :: Value -> Exp
yield value = callCC $ \k -> do
bc <- asks blockCont
local (\fc -> fc { blockCont = k }) (bc value)
retry :: Exp
retry = do
k <- asks retryCall
k
bind :: Identifier -> Value -> Exp
bind i v = do
modify ((i,v) :)
return v
infixr 1 =:=
class Bindable v where (=:=) :: Identifier -> v -> Exp
instance Bindable Value where (=:=) = bind
instance Bindable Exp where i =:= e = bind i =<< e
val :: Identifier -> Exp
val i = gets $ fromMaybe (i ++ "=UNDEFINED") . lookup i
test1 = do
"i" =:= "0"
my_while [("cond", condExp)] $
"i" += 1
val "i"
where
my_while = fcall $ do
cond <- val "cond"
if cond == "true"
then do { yield_; retry }
else return cond
a += b = a =:= (liftM $ show . (b+) . read) (val a)
condExp = do
i <- val "i"
return $ if (read i) < 10 then "true" else "false"
test2 = do
f [] $ do
"j" =:= "J"
"l" =:= "L"
mapM val (words "i j k l") >>= return . unwords
where
f = fcall $ do
"i" =:= "I"
"k" =:= "K"
yield_
test3 = do
f [] $ do
rba <- yield "J-via-yield"
yield rba
yield "M-via-yield"
mapM val (words "i j k l m") >>= return . unwords
where
f = fcall $ do
"i" =:= "I"
"j" =:= yield_
"k" =:= "K"
"l" =:= yield "Right-back-atcha!"
"m" =:= yield_
Here’s what the code does when executed:
> evalTop test1
"10"
> evalTop test2
"I J K L"
> evalTop test3
"I J-via-yield K Right-back-atcha! M-via-yield"
I must say that I really like Ruby’s semantics. So far, I find
Ruby to be a seriously cool programming language.
Posted in functional programming, programming languages, haskell, ruby
Tags evaluators, haskell, ruby
6 comments
no trackbacks

Posted by Tom Moertel
Thu, 22 Jul 2004 22:25:00 GMT
I discovered only recently about Google’s challenge to find the first ten-digit prime number in the consecutive digits of e. For fun, I solved the challenge (and the follow-up challenge), but the interesting part is a cool algorithm that I came across to compute the digits of e, one by one.
The algorithm lets you compute the digits sequentially without any pre-commitment to the total number of digits you’ll eventually take. The technique behind the algorithm can be used to compute other things, and so it’s worth a look.
If you’re interested, please take a look at my HuSi diary entry on the subject, Google challenge task and computing the digits of e, where I explain the method in detail. I’ll also refer you to Jeremy Gibbons’s paper An Unbounded Spigot Algorithm for the Digits of Pi, which is the inspiration for the method.
Posted in programming, functional programming
no comments
no trackbacks
