Kyle R. Burton on 12 Jun 2007 18:36:48 -0000


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

Re: [PLUG] Question about erlang presentation

  • From: "Kyle R. Burton" <kyle.burton@gmail.com>
  • To: "Philadelphia Linux User's Group Discussion List" <plug@lists.phillylinux.org>
  • Subject: Re: [PLUG] Question about erlang presentation
  • Date: Tue, 12 Jun 2007 14:36:42 -0400
  • Dkim-signature: a=rsa-sha1; c=relaxed/relaxed; d=gmail.com; s=beta; h=domainkey-signature:received:received:message-id:date:from:to:subject:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references; b=NN31OhHryfjLNRUTM8o37vsXkEjsRVtfSshwmyMBtaKi7eYODrPiHqqKeAxzE3cA/98jnyZulf2/kVgFJtL1LXeDWhlZDPRI3jWGTprY/pFklyyeyNTZ+hgV30O31v7oIkc0mijMzceE3Vntrq7g3KAQWlCD8f3qwZ2S7qcndVw=
  • Reply-to: Philadelphia Linux User's Group Discussion List <plug@lists.phillylinux.org>
  • Sender: plug-bounces@lists.phillylinux.org

I couldn't make the presentation (new kid born on Tuesday) so sorry about that.

> You said that = was in reality a binding instead of an assignment.
> I'm not sure I understand.  Are you saying that in erlang this
> statement:
>
> Var = 2 + 2
>
> puts something besides the number 4 into Var?

No, at the end of that expression evaluation, Var will surely point to the
value 4. However, Erlang's = is a binding operator, not an assignment
operator. Assignments insert a value into a memory location. Bindings
associated a name with a value. In Erlang, the = is "overloaded" (so to
speak) by also performing Prolog-style pattern matching. So, this
statement:

A way that was useful for me to think about it is that saying 'Var = 2 + 2' is like an assertion. You're saying that the symbol Var is (the result of) 2 + 2 (or 4). So you can also assert: 'Var = 2 + 1 + 1' or 'Var = 2 * 2' or 'Var = 4 - 2' all within the same scope and Erlang will be ok with it since you're not contradicting what you said earlier (Var = 2 + 2).

But what you can not do (in the same scope) is try to assert that Var
has a different value:  'Var = 7' would throw an error.

{car, Type, Power} = Car.

indicates multiple bindings.

I called it a "binding" operator because Erlang doesn't really have
"assignment" like imperative languages do. When you use = in Erlang,
you're not telling the compiler what to do with some particular piece of
memory, you're just telling it that "from now on, when I use X, I mean
Y".

In this case Car has to be a tuple of 3 values, the literal 'car', and two other elements which will be then bound to Type and Power. So if Car was { car, "Coupe", 400 }, Type would be "Coupe" and Power would be 400. That statement would fail if Car were { foo, "Coupe", 400 }, since the assertion that the first element of the tuple is 'car' would fail.

This feature exists in some other languages, too, in more limited form.
Lisp and Scheme have something called a "destructuring bind" which is like
the example above. This is less powerful than Erlang's pattern matching,
since it only "explodes" a list and nothing else. Prolog has full pattern
matching, however, as Erlang's was inspired by Prolog.

Common Lisp has a destructuring bind which can pick apart a tree (represented as lists):

 (destructuring-bind (a (b c)) '(1 (2 3)
   (format t "a:~a b:~a c:~a~&" a b c))

would print a:1 b:2 c:3

Scheme doesn't have one (as part of the standard library), but you
could (obviously) write one.  Scheme does have something which uses
the Erlang style of destructuring that is part of it's syntax-rules
system (http://www.xs4all.nl/~hipster/lib/scheme/gauche/define-syntax-primer.txt).


Tail recursion is a way to formulate a recursive function such that the
function does not need to return to its parent caller to calculate the
correct value. Its an optimization technique: using tail recursion allows
the compiler to reuse the existing stack frame for the function call
rather than having to create another one (as with regular recursive
functions). This saves a lot of space and allows for indefinite recursion
as your per-function space overhead is amortized to near zero on very
deep recursions.

In order to really be able to use tail recursion, though, your compiler or
language platform has to support it. Erlang supports it. C compilers do
not, in general. I think Java does not support it, either.

Java definitely does not support tail call optimization. Newer gccs have a compiler flag for it. Most Lisps support it - and to be a 'real' Scheme the implementation must support it (the Scheme standard requires it of its implementations). Haskell and other FP languages also support it. Have a look at:

 http://www-128.ibm.com/developerworks/linux/library/l-recurs.html?ca=dgr-lnxw02Recursion

which discusses tail recursion in Lisp(s) and C.


Kyle


Anything that can be expressed recursively, however, can also be expressed
iteratively. Thus, if you're using a language/platform that does not
support tail recursion, you can always drop back to the iterative form of
the algorithm(s) when you might be recursing a lot of using multiple
recursive functions concurrently.

> Thanks again for a very interesting presentation.

Doitashimashite (^_^)  I was glad that you guys liked it :)

--
Toby DiPasquale

___________________________________________________________________________
Philadelphia Linux Users Group         --        http://www.phillylinux.org
Announcements - http://lists.phillylinux.org/mailman/listinfo/plug-announce
General Discussion  --   http://lists.phillylinux.org/mailman/listinfo/plug