Showing posts with label dynamic typing. Show all posts
Showing posts with label dynamic typing. Show all posts

2011-08-25

scala instead of perl

I've used perl for years as a "better shell script", and found it perfectly natural and easy to express the things I've asked of it.
The other day I did something that seemed perfectly natural to me, I passed a list to a function that returned another list.
I expected this to work, as I would in any language.
I was testing each function separately and everything seemed fine.
So I started testing the script as a whole; that's when strange things started happening.
Lists starting containing too many values, and of the wrong kind.
So, I did some googling without really knowing what kind of problem it was; assuming the whole time that I'd written some simple semantic error or something.
What I didn't expect though was the real problem :
Perl doesn't support lists properly.

You can't have a list of lists, you can't pass a list to a function or return a list from a function.
You can have a list of list references however, or pass list references to a function, or return a list reference.
So this whole time, I'd just happened to be passing scalars around, thinking perl was a pretty straightforward language. The reality is that it isn't actually much higher level than C.

It was originally designed late eighties to early nineties, so it makes sense that the OO and functional aspects aren't as well thought out as newer languages. I guess the idea of collections being fundamental wasn't that big at the time either.

I've recently had a chance to use ruby again, and this time I've actually enjoyed it. Especially the meta programming aspect. As ruby was designed a fair bit later, it feels a lot more modern; and lists work as I expect !

I think from now on, (assuming I got a choice), I'll be using perl _only_ for very simple shell scripts, or not at all; and using more competent languages (like ruby) for anything of substance.

For this specific task, I've reimplemented it as a Scala script; and in doing so I've fixed a bunch of bugs in my original perl code.
It's also made the code run a bit faster, as well as made the code easier to change.
Scala's regex and system exec libraries aren't as succinct as perl's; but you'd have to make them first class features of the language (as perl has) to reach that goal.
It's still run as a script, so it won't be any different from the user's point of view.

2010-09-28

Further down the rabbit hole

I was just reading Ben Hutchison's blog post on functional programming:
study-functional-programming-or-be-ignorant/

and I've come to a very similar realisation, with one notable additional point

lisp.

After watching some of the Structure and Interpretation of Computer Programs lectures,
my ideas about software, programming, data and computation have all been significantly changed.
The lectures focus on the theory of computer science using lisp.

In lisp, everything is (can be) represented as a list. This includes the source code, the interpreter, the environment, as well as data structures. The biggest change to my thinking occurred when they showed that something as fundamental as the list can be defined using closures and no other data structure. Something that I thought was an atom, built in, written in assembler; was actually definable in the language using other constructs.

This actually blew my mind.
It meant that all you needed was closures, and function application.
In the scheme example they showed in the lecture, it looked something like this:
(define (cons a b) (lambda (x) (x a b)))
(define (car x) (x (lambda (a b) a)))
(define (cdr x) (x (lambda (a b) b)))

The key is returning a when you call car(head), and b when calling cdr(tail).

I was so excited by this, I decided to implement it in a language I actually understood. ie NOT lisp.
I've been playing a bit with clojure and elisp, as well as haskell and I've been reading about F# and OCaml; But I keep coming back to scala, so I implemented it in that:
type consT[H, T] = ((H,T) => Any) => Any
def cons[H,T](a:H, b:T) : consT[H,T] = x => x(a,b)
def car[H,T](x:consT[H,T]) : H = x((a:H,b:T) => a).asInstanceOf[H]
def cdr[H,T](x:consT[H,T]) : T = x((a:H, b:T) => b).asInstanceOf[T]
 Most of which is actually type annotations, which ensure that the methods are completely generic. This is in contrast to lisps dynamic typing.

Some simplification is possible, but it's still not really the scala way:
type consT[H, T] = ((H, T) => Any) => Any
def cons[H, T](a: H, b: T): consT[H, T] = _(a, b)
def car[H, T](x: consT[H, T]) = x((a, _) => a).asInstanceOf[H]
def cdr[H, T](x: consT[H, T]) = x((_, b) => b).asInstanceOf[T]
If scala were to have some more advanced type inference or dynamic typing, it might look something like:
def cons(a, b) = _(a,b)
def car(x) = x((a,_) => a)
def cdr(x) = x((_,b) => b)
But it's pretty clear that that's not likely.

The beauty of it is, the lisp and scala uses of the above code is pretty similar.
something like this in clojure/lisp:
(def a (cons 1 (cons 2 3)))
(car a)
(car (cdr a))
(cdr (cdr a))

in scala:
val a = cons(1, cons(2, 3))
car(a)
car(cdr(a))
cdr(cdr(a))
So while the library side of things may be more complicated in scala, (also type safe), the actually usage is no more complicated at all.