What are considered atoms in Scheme? - scheme

Can someone please explain or link me to any helpful resources ( I couldn't find any threads on google) that could help me understand what atoms are.

Nowadays we consider an atom an element that's not a cons-pair and that is not null. That includes:
Numbers
Strings
Symbols
Booleans
Characters
This is best expressed with the following procedure, taken from the book The Little Schemer:
(define atom?
(lambda (x)
(and (not (pair? x)) (not (null? x)))))

The term "atom" is used by several authors (McCarthy and Friedman/Felleisen, among others) to refer to a datum that is not a "cons" pair. I claim that these days, you'd be more likely to invert that, and test for "cons"-hood rather than "atom"-hood. Where are you seeing the term used?

Related

Pattern match function in Scheme Meta Circular Evaluator

I'm trying to add a pattern matching function to an existing scheme meta circular evaluator (this is homework) and I'm a bit lost on the wording of the instructions. I was hoping someone more skilled in this regard could help me interpret this.
The syntax for match should look like the following: (match a ((p1 v1) (p2 v2) (p3 v3)))
And it could be used to find length like so:
(define length (lambda (x)
(match x (('() 0)
(('cons a b) (+ 1 (length b))))))
The pattern language in the function should contain numeric constants, quoted constants, variables, and cons. If patterns are exhausted without finding a match, an error should be thrown.
I thought I understood the concept of pattern matching but implementing it in a function this way has me a bit thrown off. Would anyone be willing to explain what the above syntax is doing (specifically, how match is used in length above) so I can get a better understanding of what this function should do?
(match x (('() 0)
(('cons a b) (+ 1 (length b)))))
It may be most helpful to consider what this code would need to expand into. For each pattern, you'd need a test to determine whether the object you're trying to match matches, and you'd need code to figure out how to bind variables to its subparts. In this case, you'd want an expansion roughly like:
(if (equal? '() x)
0
(if (pair? x)
(let ((a (car x))
(b (cdr x)))
(+ 1 (length b)))
;; indicate failure to match
'NO-MATCH))
You could write that with a cond, too, of course, but if you have to procedurally expand this, it might be easier to use nested if forms.
If you're actually implementing this as a function (and not as a macro (i.e., source transformation), then you'll need to specify exactly how you can work with environments, etc.
I suggest you read the chapter four, Structured Types and the Semantics of Pattern Matching, from The Implementation of Functional Languages. The chapter is written by Simon L. Peyton Jones and Philip Wadler.

Little Schemer "S-expression" predicate

Is it true that this is an S-expression?
xyz
asks The Little Schemer. but how to test?
syntactically, i get how to test other statements like
> (atom? 'turkey)
and
> (list? '(atom))
not entirely sure how to test this...
> (list? '(atom turkey) or)
as it just returns...
or: bad syntax in: or
but anyway, knowing how to test for S-expressions is foxing me
so, as per usual, any illumination much appreciated
An "S-expression" is built of atoms via several (possibly zero) cons applications:
(define (sexp? expr)
(or
; several cases:
(atom? expr)
; or
(and (pair? expr) ; a pair is built by a cons
(sexp? (car expr)) ; from a "car"
(sexp? .........)) ; and a "cdr"
)))
This is practically in English. Nothing more to say about it (in code, I mean). Except, after defining the missing
(define (atom? x)
(not (pair? x)))
we see that (sexp? ...) can only return #t. This is the whole point to it: in Lisp, everything is an S-expression – either an atom, or a pair of S-expressions.
The previous answer is correct -- Scheme (and Lisp) are languages that are based on S-expressions. And the provided code is a great start.
But it's not quite correct that everything is an S-expression in those languages. In this case you have an expression that isn't syntactically correct, so the language chokes when it tries to read it in. In other words, it's not an S-expression.
I know it's frustrating, and honestly, not that great of an answer, but this is a great lesson in one of the Golden Rules of Computer Programming: Garbage In, Garbage Out. The fat is that you are going to get these kinds of errors simply because it isn't really feasible, when starting out programming, to test for every possible way that something isn't an S-expression without using the language itself.

How to create a Scheme definition to parse a compound S-expression and put in a normal form

Given an expression in the form of : (* 3 (+ x y)), how can I evaluate the expression so as to put it in the form (+ (* 3 x) (* 3 y))? (note: in the general case, 3 is any constant, and "x" or "y" could be terms of single variables or other s-expressions (e.g. (+ 2 x)).
How do I write a lambda expression that will recursively evaluate the items (atoms?) in the original expression and determine whether they are a constant or a term? In the case of a term, it would then need to be evaluated again recursively to determine the type of each item in that term's list.
Again, the crux of the issue for me is the recursive "kernel" of the definition.
I would obviously need a base case that would determine once I have reached the last, single atom in the deepest part of the expression. Then recursively work "back up", building the expression in the proper form according to rules.
Coming from a Java / C++ background I am having great difficulty in understanding how to do this syntactically in Scheme.
Let's take a quick detour from the original problem to something slightly related. Say that you're given the following: you want to write an evaluator that takes "string-building" expressions like (* 3 "hello") and "evaluates" it to "hellohellohello". Other examples that we'd like to make work include things like
(+ "rock" (+ (* 5 "p") "aper")) ==> "rockpppppaper"
(* 3 (+ "scis" "sors")) ==> "scissorsscissorsscissors"
To tackle a problem like this, we need to specify exactly what the shape of the inputs are. Essentially, we want to describe a data-type. We'll say that our inputs are going to be "string-expressions". Let's call them str-exprs for short. Then let's define what it means to be a str-expr.
A str-expr is either:
<string>
(+ <str-expr> <str-expr>)
(* <number> <str-expr>)
By this notation, we're trying to say that str-exprs will all fit one of those three shapes.
Once we have a good idea of what the shape of the data is, we have a better guide to write functions that process str-exprs: they must case-analyze those three alternatives!
;; A str-expr is either:
;; a plain string, or
;; (+ str-expr str-expr), or
;; (* number str-expr)
;; We want to write a definition to "evaluate" such string-expressions.
;; evaluate: str-expr -> string
(define (evaluate expr)
(cond
[(string? expr)
...]
[(eq? (first expr) '+)
...]
[(eq? (first expr) '*)
...]))
where the '...'s are things that we'll be filling in.
Actually, we know how to fill in a little more about the '...': we know that in the second and third cases, the inner parts are themselves str-exprs. Those are prime spots where recurrence will probably happen: since our data is described in terms of itself, the programs that process them will also probably need to refer to themselves. In short, programs that process str-exprs will almost certainly follow this shape:
(define (evaluate expr)
(cond
[(string? expr)
... expr
...]
[(eq? (first expr) '+)
... (evaluate (second expr))
... (evaluate (third expr))
...]
[(eq? (first expr) '*)
... (second expr)
... (evaluate (third expr))
...]))
That's all without even doing any real work: we can figure this part out just purely because that's what the data's shape tells us. Filling in the remainder of the '...'s to make this all work out is actually not too bad, especially when we also consider the test cases we've cooked up. (Code)
It's this kind of standard data-analysis/case-analysis that's at the heart of your question, and it's one that's covered extensively by curricula such as HTDP. This is not Scheme or Racket specific: you'd do the same kind of data analysis in Java, and you see the same kind of approach in many other places. In Java, the low-mechanism used for the case analysis might be done differently, perhaps with dynamic dispatch, but the core ideas are all the same. You need to describe the data. Once you have a data definition, use it to help you sketch out what the code needs to look like to process that data. Use test cases to triangulate how to fill in the sketch.
You need to break down your problem. I would start by following the HtDP (www.htdp.org) approach. What are your inputs? Can you specify them precisely? In this case, those inputs are going to be self-referential.
Then, specify the output form. In fact, your text above is a little fuzzy on this: I think I know what your output form looks like, but I'm not entirely sure.
Next, write a set of tests. These should be based on the structure of your input terms; start with the simplest ones, and work upward from there.
Once you have a good set of tests, implementing the function should be pretty straightforward. I'd be glad to help if you get stuck!

reduce, or explicit recursion?

I recently started reading through Paul Graham's On Lisp with a friend, and we realized that we have very different opinions of reduce: I think it expresses a certain kind of recursive form very clearly and concisely; he prefers to write out the recursion very explicitly.
I suspect we're each right in some context and wrong in another, but we don't know where the line is. When do you choose one form over the other, and what do you think about when making that choice?
To be clear about what I mean by reduce vs. explicit recursion, here's the same function implemented twice:
(defun my-remove-if (pred lst)
(fold (lambda (left right)
(if (funcall pred left)
right
(cons left right)))
lst :from-end t))
(defun my-remove-if (pred lst)
(if lst
(if (funcall pred (car lst))
(my-remove-if pred (cdr lst))
(cons (car lst) (my-remove-if pred (cdr lst))))
'()))
I'm afraid I started out a Schemer (now we're Racketeers?) so please let me know if I've botched the Common Lisp syntax. Hopefully the point will be clear even if the code is incorrect.
If you have a choice, you should always express your computational intent in the most abstract terms possible. This makes it easier for a reader to figure out your intentions, and it makes it easier for the compiler to optimize your code. In your example, when the compiler trivially knows you are doing a fold operation by virtue of you naming it, it also trivially knows that it could possibly parallelize the leaf operations. It would be much harder for a compiler to figure that out when you write extremely low level operations.
I'm going to take a slightly-subjective question and give a highly-subjective answer, since Ira already gave a perfectly pragmatic and logical one. :-)
I know writing things out explicitly is highly valued in some circles (the Python guys make it part of their "zen"), but even when I was writing Python I never understood it. I want to write at the highest level possible, all the time. When I want to write things out explicitly, I use assembly language. The point of using a computer (and a HLL) is to get it to do these things for me!
For your my-remove-if example, the reduce one looks fine to me (apart from the Scheme-isms like fold and lst :-)). I'm familiar with the concept of reduce, so all I need to understand it is figure out your f(x,y) -> z. For the explicit variant, I had to think it for a second: I have to figure out the loop myself. Recursion isn't the hardest concept out there, but I think it is harder than "a function of two arguments".
I also don't care for a whole line being repeated -- (my-remove-if pred (cdr lst)). I think I like Lisp in part because I'm absolutely ruthless at DRY, and Lisp allows me to be DRY on axes that other languages don't. (You could put in another LET at the top to avoid this, but then it's longer and more complex, which I think is another reason to prefer the reduction, though at this point I might just be rationalizing.)
I think maybe the contexts in which the Python guys, at least, dislike implicit functionality would be:
when no-one could be expected to guess the behavior (like frobnicate("hello, world", True) -- what does True mean?), or:
cases when it's reasonable for implicit behavior to change (like when the True argument gets moved, or removed, or replaced with something else, since there's no compile-time error in most dynamic languages)
But reduce in Lisp fails both of these criteria: it's a well-understood abstraction that everybody knows, and that isn't going to change, at least not on any timescale I care about.
Now, I absolutely believe there are some cases where it'd be easier for me to read an explicit function call, but I think you'd have to be pretty creative to come up with them. I can't think of any offhand, because reduce and mapcar and friends are really good abstractions.
In Common Lisp one prefers the higher-order functions for data structure traversal, filtering, and other related operations over recursion. That's also to see from many provided functions like REDUCE, REMOVE-IF, MAP and others.
Tail recursion is a) not supported by the standard, b) maybe invoked differently with different CL compilers and c) using tail recursion may have side effects on the generated machine code for surrounding code.
Often, for certain data structures, many of these above operations are implemented with LOOP or ITERATE and provided as higher-order function. There is a tendency to prefer new language extensions (like LOOP and ITERATE) for iterative code over using recursion for iteration.
(defun my-remove-if (pred list)
(loop for item in list
unless (funcall pred item)
collect item))
Here is also a version that uses the Common Lisp function REDUCE:
(defun my-remove-if (pred list)
(reduce (lambda (left right)
(if (funcall pred left)
right
(cons left right)))
list
:from-end t
:initial-value nil))

Idiomatic scheme and generic programming, why only on numbers?

In Scheme, procedures like +, -, *, / works on different types of numbers, but we don't much see any other generic procedures.
For example, length works only on list so that vector-length and string-length are needed.
I guess it comes from the fact that the language doesn't really offer any mechanism for defining generic procedure (except cond of course) like "type classes" in Haskell or a standardized object system.
Is there an idiomatic scheme way to handle generic procedures that I'm not aware of ?
Keeping in mind that all "different types of numbers" are all scheme numbers (i.e. (number? n) equals #t) - this behavior actually makes sense. +, -, *, / and all other arithmetic operators operate on numbers only (even though in other languages they would be classified as different number types int, long, float, etc...) This is due to the fact that you can't explicitly declare number types in scheme.
If you really need a generic solution, besides using external libraries, the easiest way is to roll your own:
(define org-length length)
(define (length x)
(cond
((string? x) (string-length x))
((vector? x) (vector-length x))
; keep going ...
(else (org-length x))))
No, but you can build your own. Welcome to Scheme!
In the past I've used Swindle to provide generic functions. It's bundled with PLT Scheme. It worked well for me, but it's been a few years. There may be other alternatives out there now.
Read SICP, sections 2.4 and 2.5, which cover the implementation of procedures that can operate on generic data types by means of attaching "tags" to data objects. It's also in lecture 4-B of that MIT video series.
You really want to have an object system for that. You may want to have a look at Tiny CLOS, for instance, which is the de-facto standard object system for Chicken Scheme (see the reference manual), but seems to be available for most Scheme implementations.
Finally, I found out a very neat solution in PLT Scheme :
(require (rename-in scheme [length list-length]))
(define length
(λ (x)
((cond [(list? x) list-length]
[(string? x) string-length]
[(vector? x) vector-length]
[else (error "whatever")]) x)))
(length '(a b c))
(length "abc")
(length #(1 2 3))

Resources