Carl Love

Carl Love

28025 Reputation

25 Badges

12 years, 313 days
Himself
Wayland, Massachusetts, United States
My name was formerly Carl Devore.

MaplePrimes Activity


These are replies submitted by Carl Love

@Scot Gould Please give a practical example such as might be used in an introductory course using Maple where this evaluation-level stuff makes any difference. The examples in this thread are highly contrived, not practical.

I think that you've misconstrued the comment about other programming languages. In a language without symbolic variables, it's impossible for there to be any distinction between full and one-level evaluation. Symbolic variables means variables that have no value other than their own name.

@Mariusz Iwaniuk Your scaling along the time axis is unrealistic. You have t=20 matched to 2010 and 2015.

@janhardo You wrote:

  • This is not looking here above anymore on a procedure definition with proc().. end proc;? 
    But it seems to be a procedure. 
    Its function made by the operator -> then.

Yes, there's no significant performance difference between the proc() end proc and ()-> forms. One insignificant difference, unrelated to performance, that you've noticed is how these forms are displayed in prettyprinted or 2-D output. If you want to suppress that output, you could end the procedure definition with a colon (:) instead of a semicolon (;). This is what I assumed you meant by "outcomment".

  • Another point about a while clause of the do statement in relation to summing up a list of numbers. I can take a partial sum of the list,therefore should be needed a while clause.

Your English is a bit difficult for me to understand. Are you saying that you want a procedure for the partial sums of a list? Here is such a procedure:

PartialSums:= (L::list(algebraic))-> local S:= 0, x; [seq((S+= x), x= L)];  

The command ListTools:-PartialSums also handles this. This procedure does not need a while clause.

  • PR:=proc(A,N)   # PR is product
       p:=1;
       for i from 1 to N do p:=p*A[i] end do:
    end proc;

Your solution is pretty good. I'd like to point out some issues. Here's my version:

PR:= (A::indexable)->
    if numelems(A)=0 then 1 else local p:=  1, x; for x in eval(A) do p*= x od fi
:  

Issues:

  1. It is not necessary or desirable to pass the size N. The size can be determined inside the procedure using numelems. If A is restricted to lists and sets, then nops can be used. I'm sure that you'll see nops somewhere in Betounes's book.
  2. In your procedure, and i should be declared local.
  3. Your procedure will return NULL (which displays as nothing at all) if A is empty. The usual mathematical convention is that when an associative operator with identity is applied to an empty set of operands, its identity is returned. That means that 1 should be returned.
  4. It is not necessary or desirable to index A to extract its elements. Use the in form of for-do loop instead.
  5. The eval is only needed for certain types of that I probably shouldn't detail right now. If is restricted to lists and sets, eval is not needed.
  • To make a factorial 4! from the list A you must fill it with natural numbers : that is not handy

Yes, of course. It was not the point of my exercise that you would directly use this procedure to compute factorials. But the next exercise is to write a procedure that computes the factorial of a nonnegative integer n.

@janhardo Note that there's no practical difference between a procedure written as proc(...) ... end proc and one written as (...)-> .... For example,

f1:= proc(x) x^sin(x) end proc versus f2:= x-> x^sin(x).

@Scot Gould I have not memorized Maple help pages in the sense of "photographic memory". The way my memory works is akin to a Maple table whose indices are "question that has an answer" and whose entries are "help page that has the answer". I've read some pages (?type,structure, ?operators,precedence) hundreds of times.

I think that any efficiency gain due to shallow evaluation is worth exploiting. The only drawback to it that I'm aware of is the occasional "inconsistency" in the top-level results that you noted. That inconsistency is always resolved by doing one more top-level evaluation.

Like you, I overwhelmingly tend to use "bottom-up" evaluation rather than "top-down". 

@dharr I appreciate your concern for better error messages. Like I said, sometimes the message needs to come from the argument checking. In those cases the end user will never see the error message, and the arguments are passed to another procedure.

The name speclist is by analogy with the standard type names specfuncspecindex, and specop; though your listcontaining is good also.

@Scot Gould Yes, there is a good reason for that. The level of evaluation of variables within procedures is minimal (one level I think), for efficiency, but there's more evaluation at the top level (full evaluation up to removing one level of unevaluation quotes), because that's what's usually wanted for a top-level result. The level of evaluation also depends on whether it's a local or global that's being evaluated. See ?eval.

@dharr If the issue that you raised was of concern, then I'd address it by defining a type for this:

TypeTools:-AddType(
    speclist,
    proc(e, T::type, n::nonnegint:= (), {distinct::truefalse:= false})
        e::list(T) and 
        (n<>() implies nops(e)=n) and
        (distinct implies (nops = nops@{op})(e))
    end proc
);

Then Rouben could define his procedure as 

P:= proc(Z::speclist(identical(a,b,c,d), 2, distinct)) end proc

and the error messages would be more reasonable.

 

There are sometimes programmatic reasons why you'd prefer an "invalid input" error over an error produced from within the procedure. One of those is for use with the overload command.

In addition, all that Acer said about tables also applies to Records because, like tables, they are mutable and have property last_name_eval.

@Rouben Rostamian  

Maple contains a whole sublanguage or algebra for type expressions. The parts of it that I used above are (is any single expression):

  1. If is a type, then e::T iff type(e,T).
  2. e::(T &under f) iff f(e)::T.
  3. If is a numeric constant (such as the 2 in my code), then e::C iff e=C.
  4. e::And(T1, T2) iff e::T1 and e::T2, and likewise for more types.
  5. e::[T1,T2] iff e::list and nops(e)=2 and e[1]::T1 and e[2]::T2, and likewise for any number of types.
  6. e::identical(a,b) iff e in {a,b}, and likewise for any number of expressions.
  7. e::list(T) iff e::list and andmap(type, e, T).

Andand, and andmap all follow the McCarthy evaluation rule: Operands are evaluated left to right (or in order), and the evaluation stops if a false occurs.

There is also a perhaps-more-familiar algebra of functional operators. The parts of it that I used above are (the () represents any argument sequence)

  1. {f,g}() {f(), g()}, and likewise for any number of operators.
  2. (f@g)() = f(g()), and likewise for any number of operators.
  3. [f,g]() = [f(), g()], and likewise for any number of operators.
  4. a &f b `&f`(a,b) (regardless of whether the latter has been formally defined).
  5. &f has higher precedence than @, so the parentheses are required in 2 &under (nops@{op}).

The most important help pages on this material are ?type,structure, ?evalapply, ?operators,precedence, ?&, and ?use (but only the part towards the end of Description where it talks about operators). Let me know if you have any questions.

@janhardo is both the sum and the return value. It must be initilized to 0.

This procedure does the same thing using a for-in-do loop:

SumList:= proc(L::list)
local S:= 0, x;
    for x in L do
        S:= S + x
    od;
    S
end proc:

An alternative formulation is

SumList:= (L::list(algebraic))-> 
    if L=[] then 0 else local S:= 0, x; for x in L do S:= S+x od fi
:

In this formulation, the return value is either 0 or the last computed in the loop, so no at the end is needed.

S:= S+x is equivalent to S+= x. This feature was added in Maple 2018 or Maple 2019, so you won't find it in your book.

If you're having trouble with the factorial, then do this exercise first: Write a procedure to find the product of a list of numbers.

@janhardo From closely reading your loop attempts, I see that you're really struggling with it. Here's a simple straightforward procedure with a loop to sum the elements of a list of arbitrary length:

SumList:= proc(L::list)
local S:= 0, i;
    for i to nops(L) do
        S:= S + L[i]
    od;
    S
end proc;

Please study this thoroughly and let me know if you have any questions.

@janhardo I think that I'll wait until you've learned the while clause of the do statement before I explain further. But note that it's not an until statement; the until part is a clause that terminates the preceding do statement.

In my opinion, Maple is not well suited to derive the displayed form from your typed form. If, however, you want to verify whether the two forms are equivalent, Maple is good at that.

I totally understand why you'd want to come up with contrived examples such as you have been as a means of experimentation. I do the same thing myself. So, don't take my Answers too harshly; I encourage you to experiment.

Pedagogic advice: You'll learn a lot if you try to remove from your examples everything that doesn't cause the anomaly. In all intellectual pursuits, there is an art to creating good examples.

First 193 194 195 196 197 198 199 Last Page 195 of 708