[e-lang] Comments on SICP in E code

Kevin Reid kpreid at mac.com
Wed Dec 27 18:37:14 CST 2006


My comments on the code at

   <http://www.codepoetics.com/wiki/index.php? 
title=Topics:SICP_in_other_languages:E:Chapter_2>

. I've also made the changes that I think are appropriate and don't  
guess are against the purpose of the code.

> def gcd(a, b) {
>    if (b == 0) {
>       return a
>    } else {
>       return gcd(b, a % b)
>    }
> }

This sort of code can also be written in more functional style:

def gcd(a, b) {
    return if (b == 0) {
              a
           } else {
              gcd(b, a % b)
           }
}

or

def gcd(a, b) {
    return if (b == 0) {
       a
    } else {
       gcd(b, a % b)
    }
}

or

def gcd := fn a, b { if (b == 0) {
                         a
                      } else {
                         gcd(b, a % b)
                      }
                    }

> def nil() { }

Since nil here is of interest as a value, and not particularly as a  
function, it should be:

def nil {}

> def list(xs) {
>    if (xs.size() == 0) {
>       return nil
>    } else if (xs.size() == 1) {
>       return cons(xs[0], nil)
>    } else {
>       return cons(xs[0], list(xs(1)))
>    }
> }

The second case is unnecessary. I would write this as:

def list(xs) {
    if (xs =~ []) {
       return nil
    } else {
       return cons(xs[0], list(xs(1)))
    }
}

> def islist(xs) {
>    try {
>       if (xs == nil) {
>          return true
>       } else if (xs[1] == nil) {
>          return true
>       } else {
>          return islist(cdr(xs))
>       }
>    } catch err {
>       return false
>    }
> }

Again, the second case is unnecessary.

Don't name an unused variable except for documentation; use the  
ignore pattern instead:

    } catch _ {

Also, this function would be better written with patterns:

def islist(xs) {
    return switch (xs) {
       match ==nil    { true }
       match [_, cdr] { islist(cdr) }
       match _        { false }
    }
}

Or list guards:

def islist(xs) {
    if (xs == nil) {
       return true
    } else {
       def xsList := List.coerce(xs, fn _ { return false })
       return islist(cdr(xs))
    }
}

Or write the whole thing as a recursive composed guard:

interface Nil {}
def nil implements Nil {}

def LList := Tuple[any, LList] | Nil

def islist(xs) {
    return xs =~ _ :LList

    # more explicit form:
    # List.coerce(xs, fn _ { return false }); return true
}

I have not made this change in case the use of explicit ifs is  
significant.

> def str(s) { return `$s` }

def str(x) { return E.toString(x) }

def str := E.toString

> def min(x, y) { return if (x <= y) { return x } else { return y } }

This can be written as x.min(y). I have not made this change.

>    def print_rat(x) {
>       println (str(numer(x)) + "/" + str(denom(x)))
>    }

Use the printer, not concatenation.

    def print_rat(x) {
       println(numer(x), "/", denom(x))
    }

I'm skipping over most of the rationals code.

>       def dispatchx(m) {
>          if (m == 0) {
>             return x
>          } else if (m == 1) {
>             return y
>          } else {
>             throw ("Argument not 0 or 1 -- CONS " + str(m))
>          }
>       }

       def dispatchx(m) {
          return switch (m) {
             match ==0 { x }
             match ==1 { y }
             match _ {
                throw(`Argument not 0 or 1 -- CONS $m`)
          }
       }

I have not made this change except for the throw; I assume given the  
definition of str(_) above that `` is acceptable.

Also, dispatchx could be written more idiomatically as an object with  
multiple methods; in fact, it would be an ordinary E object definition.

-- 
Kevin Reid                            <http://homepage.mac.com/kpreid/>




More information about the e-lang mailing list