Pattern matching function definitions are easy to do in Lisp.
But given the nature of Lisp, much of the pattern matching then needs to be done at runtime - which leads to less efficient code and invites people to write totally inefficient code.
Pattern matching function definitions are easy to do in Lisp.
But given the nature of Lisp, much of the pattern matching then needs to be done at runtime - which leads to less efficient code and invites people to write totally inefficient code.
Take[{a,b,c,d},2] --> {a,b}
Take[{a,b,c,d},-2] -> {c,d}
Take[{a,b,c,d},{1,3}] -> {a,b,c}
Take[{a,b,c,d},{1,-1,2}] -> {a,c}
Take[{{a,b,c,d},{1,2,3,4},{5,6,7,8}},2,2] -> {{a, b}, {1, 2}}
etc. In my book this is clearly useful, and its only scratching the surface. ( {} is actually List[] in Mathematica FullForm ... )
The point of symbolic representation is to represent the intended meaning. Its nothing about the "internal" implementation. Using symbols and simple tree structures to compactly express stuff is extremely powerful, and not coincidentally the essential way that human language works.
Sure, with a sufficiently dynamic language you can implement such functionality. The problem with Lisp is that by default symbols want to evaluate, and if you want to treat them symbolically you have to operate in a "special" mode. This makes things too complicated. There is a reason you don't see meaning represented by structure in pretty much any other language besides Mathematica.
A function like Take is easy to write in Lisp. Lisp has many similar functions like that - but with a better interface.
> There is a reason you don't see meaning represented by structure in pretty much any other language besides Mathematica.
Could it really be that you missed the AI software that has been written in Lisp in the last five decades?
Sounds like a case of blub. You look at Mathematica and see some weird stuff that is probably equivalent in power to multimethods or whatever, I look at Lisp and think how can I possibly live without civilized pattern matching.
As far as Lisp-based AI goes, its in fact very easy to miss it, but this is probably not the thread to get into Lisp's cultural issues.
I usually implement it as a reader macro. :)
Yep.
My comment was about implementing one's own Lisp reader.
(define *reader-macros* `(
(#\' ,(lambda () (list 'quote (read))))))
instead of (case dispatch-char
((#\') (list 'quote (read)))
...)QUOTE is a special operator in Lisp that causes the evaluator to return its argument unevaluated.
(quote a) -> a
(quote (+ 1 2)) -> (+ 1 2)
(quote "abc") -> "abc"
Mathematica has a different strategy for computation, one that is based on rewrite rules. Expressions are rewritten until they can't no longer be rewritten.In Lisp evaluation
(+ a a)
gives an error if the variable A has no value.In Mathematica it would be reduced to
(* 2 a) ; in Lisp syntax
if A has no value.But that has little to do with the processing capabilities of Lisp. A function like Take can be written very natural in Lisp - there is NO special mode needed. The function takes data and computes results.
You may want to get out of your Mathematica blub and learn some Lisp. Writing the 'Take' function is a good exercise. Stuff like that are basic exercises in Lisp courses.
SolvePoly[a_*x+b_=0] := { -b/a }
SolvePoly[a_*x^2+b_*x+c_=0] := \
{ (-b + sqrt(b^2-4*a*c))/2a, (-b - sqrt(b^2-4*a*c))/2a }
SolvePoly[_] := "I only took high school algebra"
Of course, in principle one could write a pattern matching macro in lisp, and I imagine there are already some halfway implementations of it. That's pretty much just Turing Equivalence.You need also differentiate between 'pattern matching' and 'rewrite system'. Pattern matching is just taking a pattern, some data and see if it matches.
(match '(+ (* ?a x) ?b) '(+ (* 123.0 x) z)) -> T
Routines like the above are found in many books about Lisp and have been provided in Lisp libraries for decades.Specifying rewrite rules with patterns for mathematical purposes (simplification, integration, differentiation, ...) is also almost as old as Lisp. Norvig's book 'Paradigm's of AI Programming' explains how it is implemented in Lisp. These things are at the heart of several computer algebra systems written in Lisp - like Macsyma.
(defun solve-poly (p)
(if (match '(+ (* ?a x) ?b) poly))
(-b/a where b, a come from (extract-values-from-pattern-match poly))
(some code for second order)
))
(Some code borrowed from lispm's comment. Not sure which library the match function comes from.)The greater point is that if this is so, one might as well deal in a model of computation that is a natural fit for that way of thinking.
I've been doing a lot of work in Scala and Actionscript. How I wish they had that family of functions in full generality. Why are they missing from most languages? Because that is not how people think in them.
Actually, this is done in Lisp and Prolog all the time.
Off the top of my head: J, K, Haskell, and Joy have take functions, and writing them in Lisp and Prolog is not difficult.
CL-USER 58 > (take '(a b c d) 2)
(A B)
CL-USER 59 > (take '(a b c d) -2)
(C D)
CL-USER 60 > (take '(a b c d) '(0 3))
(A B C)
CL-USER 61 > (take '(a b c d) '(0 -1 2))
(A C)
CL-USER 62 > (take '((a b c d) (1 2 3 4) (5 6 7 8)) 2 2)
((A B) (1 2))
That was easy. (defun take-1 (it what)
(cond ((eq what :all) it)
((eq what :none) nil)
((and (numberp what) (plusp what))
(subseq it 0 what))
((and (numberp what) (minusp what))
(last it (- what)))
((and (consp what)
(= (length what) 1)
(numberp (first what)))
(nth (first what) it))
((and (consp what)
(= (length what) 2)
(numberp (first what))
(numberp (second what)))
(let ((end (if (minusp (second what))
(+ (length it) (second what))
(second what))))
(subseq it (first what) end)))
((and (consp what)
(= (length what) 3)
(numberp (first what))
(numberp (second what))
(numberp (third what)))
(let ((end (if (minusp (second what))
(+ (length it) (second what))
(second what))))
(loop for e = (subseq it (first what)) then (nthcdr (third what) it)
for i from (first what) below end by (third what)
collect (first e))))))
(defun take (thing &rest description)
(cond ((null description) nil)
((and (consp description)
(= (length description) 1))
(take-1 thing (first description)))
(t (loop for e in (take-1 thing (first description))
collect (apply #'take e (rest description))))))So you're saying that variable bindings should be lazy? That if a symbol is not bound to a value, it should be treated as an unevaluated symbol?
I'm not quite certain what your point is. The actual functionality of Take can be easily replicated in most languages, and indeed, most languages have a version of Take called "slice".
But if your example is meant to demonstrate why lazy symbol evaluation is good, then I'm afraid it fails on that point too. There doesn't seem to be anything in your example that is particularly noteworthy.
Could you perhaps explain your point in more detail?