sicp 2.4.3 data directed programming and additivity, scheme - scheme

Could some provide clarification to the example of complex arithmetic decribed in the chapter. I can not understand one point. I would appreciate any help.
The problem is the following:
There are two packages with similiar naming of procedures.
The first one is "(install-rectangular-package)". The second one is "(install-polar-package)". In addition, a procedure is defined:
(define (make-from-real-imag x y)
(get 'make-from-real-imag 'rectangular) x y))
i type in scheme interperter
(install-rectangular-package)
(install-polar-package)
(make-from-real-imag 3 5)
and it works. what i do not understand how "get" inside "make-from-real" finds proper function in the proper package. when the string "(get 'make-from-real-imag 'rectangular)" is executed ,it replaces by "(lambda (x y) (tag (make-from-real-imag x y))))" but how it knows that it has to call function inside "(install-rectangular-package)" but not in "(install-polar-package)".

The chapter includes some sentences that say you are simply supposed to assume that the procedures put and get exist:
To implement this plan, assume that we have two procedures, put and get, for manipulating the operation-and-type table:
(put <op> <type> <item>)
installs the <item> in the table, indexed by the <op> and the <type>.
(get <op> <type>)
looks up the <op>, <type> entry in the table and returns the item found there. If no item is found, get returns false.
For now, we can assume that put and get are included in our language.
So, now we must ask for a clarification of your question:
Are you asking "how can implement a procedure like install-rectangular-package so that after (install-rectangular-package) is evaluated, the get procedure can lookup the desired operations?"
Or are you asking "how does get itself work?"
Or are you asking: "Even if we assume such a table for supporting put and get exists, how can the presented code work, where it installs multiple distinct functions with names like real-part (and imag-part, etc) even though the one real-part comes from the rectangular package, and another real-part comes from the polar package?"
If you are asking the first question, the answer is: install-rectangular-package simply calls put with the appropriate arguments to extend the lookup table that get will access.
If you are asking the second question, then you will need to see how put and get are implemented, which is discussed in Chapter 3. But the quick answer is: You could use a data structure that stores a record of every {<op>, <type>, <item>} triple inserted by put. The book describes one way to do this, where you just build up a list of entries.
(The main interesting thing that any implementation of put and get needs to do is imperatively modify some hidden state. The book uses the set-cdr! operation to do this. The requirement to use some form of imperative operation is probably the reason why they waited until Chapter 3 to describe the implementation of put and get.)
If you are asking the third question, the answer is "by the magic of lexical scoping"
The definition of install-rectangular-package has a collection of internal definitions, and install-polar-package has another collection of internal definitions. Even though there is overlap between the names chosen in the two definitions, installing the polar package does not overwrite the functions previously defined by the rectangular package.
(It is important to distinguish here between the name used in a function definition versus the function value/object (which you might think of as the (lambda (x y) ...)) itself. Even though install-rectangular-package and install-polar-package reuse the same names, they are creating distinct function values, and those distinct values are then being put into the put/get table, without any significance attached to the name used to originally define them.)
Even though the picture of the put/get table in the book looks like:
the entries in the table are not names. They are instead function objects. Other local definitions of real-part or imag-part will not affect the entries that were installed by install-rectangular-package nor install-polar-package; the only way to affect those entries is to call put itself with the matching <op> and <type> arguments to overwrite the previous cell in the table.
For more discussion of lexical scope and ways to think about local function definitions, I recommend this part of HtDP ("HtDP" stands for "How to Design Programs", which, like SICP, is an intro to programming, but written in a fashion that spells things out a bit more than SICP does; see also this paper comparing SICP and HtDP.)

Related

Is there a difference between fun(n::Integer) and fun(n::T) where T<:Integer in performance/code generation?

In Julia, I most often see code written like fun(n::T) where T<:Integer, when the function works for all subtypes of Integer. But sometimes, I also see fun(n::Integer), which some guides claim is equivalent to the above, whereas others say it's less efficient because Julia doesn't specialize on the specific subtype unless the subtype T is explicitly referred to.
The latter form is obviously more convenient, and I'd like to be able to use that if possible, but are the two forms equivalent? If not, what are the practicaly differences between them?
Yes Bogumił Kamiński is correct in his comment: f(n::T) where T<:Integer and f(n::Integer) will behave exactly the same, with the exception the the former method will have the name T already defined in its body. Of course, in the latter case you can just explicitly assign T = typeof(n) and it'll be computed at compile time.
There are a few other cases where using a TypeVar like this is crucially important, though, and it's probably worth calling them out:
f(::Array{T}) where T<:Integer is indeed very different from f(::Array{Integer}). This is the common parametric invariance gotcha (docs and another SO question about it).
f(::Type) will generate just one specialization for all DataTypes. Because types are so important to Julia, the Type type itself is special and allows parameterization like Type{Integer} to allow you to specify just the Integer type. You can use f(::Type{T}) where T<:Integer to require Julia to specialize on the exact type of Type it gets as an argument, allowing Integer or any subtypes thereof.
Both definitions are equivalent. Normally you will use fun(n::Integer) form and apply fun(n::T) where T<:Integer only if you need to use specific type T directly in your code. For example consider the following definitions from Base (all following definitions are also from Base) where it has a natural use:
zero(::Type{T}) where {T<:Number} = convert(T,0)
or
(+)(x::T, y::T) where {T<:BitInteger} = add_int(x, y)
And even if you need type information in many cases it is enough to use typeof function. Again an example definition is:
oftype(x, y) = convert(typeof(x), y)
Even if you are using a parametric type you can often avoid using where clause (which is a bit verbose) like in:
median(r::AbstractRange{<:Real}) = mean(r)
because you do not care about the actual value of the parameter in the body of the function.
Now - if you are Julia user like me - the question is how to convince yourself that this works as expected. There are the following methods:
you can check that one definition overwrites the other in methods table (i.e. after evaluating both definitions only one method is present for this function);
you can check code generated by both functions using #code_typed, #code_warntype, #code_llvm or #code_native etc. and find out that it is the same
finally you can benchmark the code for performance using BenchmarkTools
A nice plot explaining what Julia does with your code is here http://slides.com/valentinchuravy/julia-parallelism#/1/1 (I also recommend the whole presentation to any Julia user - it is excellent). And you can see on it that Julia after lowering AST applies type inference step to specialize function call before LLVM codegen step.
You can hint Julia compiler to avoid specialization. This is done using #nospecialize macro on Julia 0.7 (it is only a hint though).

How do I reinstate constraints collected with copy_term/3 in SICStus Prolog?

The documentation says that
copy_term(+Term, -Copy, -Body) makes a copy of Term in which all
variables have been replaced by new variables that occur nowhere
outside the newly created term. If Term contains attributed
variables, Body is unified with a term such that executing Body
will reinstate equivalent attributes on the variables in Copy.
I'm previously affirming numerical CLP(R) constraints over some variables, and at some point I collect these constraints using copy_term/3. Later, when I try to reinstate the constraints using 'call(Body)', I get an "Instantiation error" in arguments of the form [nfr:resubmit_eq(...)]
Here's a simplified example that demonstrates the problem:
:-use_module(library(clpr)).
{Old>=0, A>=0,A=<10, NR= Old+Z, Z=Old*(A/D)}, copy_term(Old,New,CTR), call(CTR).
Results in:
Instantiation error in argument 1 of '.'/2
! goal: [nfr:resubmit_eq([v(-1.0,[_90^ -1,_95^1,_100^1]),v(1.0,[_113^1])])]
My question is: how do I reinstate the constraints in Body over New? I haven't been able to find concrete examples.
copy_term/3 is a relatively new built-in predicate, that has been first introduced in SICStus about 2006. Its motivation was to replace the semantically cumbersome call_residue/2 which originated from SICStus 0.6 of 1987 by a cleaner and more efficient interface that splits the functionality in two:
call_residue_vars(Goal, Vars) which is like call(Goal) and upon success unifies Vars with a list variables (in unspecified order) that are attached to constraints and have been created or affected in Goal.
copy_term(Term, Copy, Body) like copy_term/2 and upon success unifies Body with a term to reinstate the actual constraints involved. Originally, Body was a goal that could be executed directly. Many systems that adopted this interface (like SWI, YAP) however, switched to use a list of goals instead. This simplifies frequent operations since you have less defaultyness, but at the expense of making reinstating more complex. You need to use maplist(call,Goals).
Most of the time, these two built-in predicates will be used together. You are using only one which makes me a bit suspicious. You first need to figure out which variables are involved, and only then you can copy them. Typically you will use call_residue_vars/2 for that. If you are copying only a couple of variables (as in your exemple) you are effectively projecting the constraints on these variables. This may or may not be your intention.
This is simply a bug in CLPR, which is unsupported. We lost touch with the CLPR supplier a long time ago.

require/typed in typed racket... examples?

I'm trying to do use the science.plt module in a typed racket program, but I'm having a hard time understanding how to use the require/typed form properly. I've read the docs repeatedly, but I guess I don't quite understand what exactly I'm trying to produce with the form.
In the
[struct name ([f : t] ...)]
form, is the name a name I should expect to find in the module I want to require, or am I making it up for use within my own program?
Probably the most helpful thing for me would be an example or three of require/typed applied to untyped racket modules.
Or if I'm misunderstanding this real deeply and one cannot use untyped modules in a typed program, how should I go about structuring things? I really just need the random number and random distribution functionality from the science.plt module, and don't expect to have any other imports, at this point.
Did you have a look at the Typed Racket reference page for require/typed? There are several examples there showing how to import from untyped modules.
The name expression in the [#:struct name ([f : t] ...) struct-option ...] clause is supposed to be the name of a structure type.
That is, if you have a struct like (struct point (x y), the name is supposed to be point.

Name a list in Scheme

I'm trying to make an array-like data structure in Scheme, and since I need to refer to it (and alter it!) often, I want to give it a name. But from what I've read on various tutorial sites, it looks like the only way to name the list for later reference is with define. That would be fine, except it also looks like once I initialize a list with define, it becomes more complicated altering or adding to said list. For example, it seems like I wouldn't be able to do just (append wordlist (element)), I'd need some manner of ! bang.
Basically my questions boil down to: Is define my only hope of naming a list? And if so, am I stuck jumping through hoops changing its elements? Thanks.
Yes, define is the way for naming things in Scheme. A normal list in Scheme won't allow you to change its elements, because it's immutable - that's one of the things you'll have to learn to live with when working with a functional data structure. Of course you can add elements to it or remove elements to it, but those operations will produce new lists, you can't change the elements in-place.
The other option is to use mutable lists instead of normal lists, but if you're just learning to use Scheme, it's better to stick to the immutable lists first and learn the Scheme way to do things in terms of immutable data.
Yes, define is the way to do "assignment" (really naming) in Scheme. Though, if you're writing some kind of package, you might consider wrapping the whole thing inside of a function and then using let to define something you refer to.
Then, of course, you have to have some sort of abstraction to unwrap the functions inside of your "package."
See SICP 2.5 Building Systems with Generic Operations
http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-18.html#%_sec_2.5
(append wordlist (element)) is creating a new list. What you might want is to use set! to redirect a reference to the new list, or define a reference to the new list using the same symbol's name.

Parameter Passing in Scheme

Can anyone help me out understanding the various parameter passing modes in Scheme? I know Scheme implements parameter passing by value. But how about other modes?
Is there any good documentation for parameter passing in Scheme?
Scheme has only call-by-value function calls. There are other alternatives that can be implemented within the language, but if you're a beginner then it's best to not even try them at this point. If you're looking for a way to pass values "by reference" -- then one option that can sort of make it is to use macros, but you really shouldn't go there. Instead, some Scheme implementations like PLT Scheme provide a "box value": this is a kind of a container that is used like this:
You create a box holding <something> with (box <something>)
You get the value that is stored in a box with (unbox <some-box>)
You change the value that is stored in a box with (set-box! <some-box> <new-value>)
Given these two, you can use such box objects "by value", but their contents is actually a reference. This is very much like C, where all values (most, actually) are passed by-value, yet some of these values can be pointers that you can mutate. BTW, it's best to avoid even these: in Scheme, functional programming is the more common choice and it is therefore better to start with that.
(Once you are more fluent with Scheme, and if you're using a Scheme with sufficient abstractions, then you can learn how to mimic lots of alternatives too.)
To add a bit more...
The four fundamental parameter-passing conventions are call-by-value, call-by-reference, call-by-name, and call-by-need. Scheme, as a "mostly functional" language, relies on call-by-value; variables, once created, generally aren't changed. The other three conventions are pretty similar and you can still do them in Scheme by passing around your values in boxes (using box and unbox), and the boxes act as pointers to values.
Generally, if you find that you need to use call-by-reference in a function, you should probably rethink how you're implementing the function and make it purely functional. Modifying a variable after it's been created using set! is a "side-effect" and is typically avoided in functional programming.

Resources