Hello! I was watching this lecture https://courses.cs.washington.edu/courses/cse341/18au/videos/unit5/captioned/085-racket-lists.m4v and I was trying how the function “my-append” works.
; append
(define (my_append xs ys)
(if (null? xs)
ys
(cons (car xs) (my_append (cdr xs) ys))) ; Instructor : "Cons the first element of the Xs on the result of Appending the rest of Xs onto Ys"
; My interpretation of paranthesis, I suppose we start from inner to outer :
; (0) cdr xs, takes the tail of xs "list/pair"
; (1) finish the recursive call to my append
; (2)there is a call to cons
; (3) the "if" conditional
; (4) and the "define" paranthesis
in my class we did first SML, and now the transition to Racket seems so weird and strange. So is I don’t really understand how "(cons (car xs) (my_append (cdr xs) ys)))" works. I mean, I don’t really understand Racket ( Java and Python was logical and easy to “vizualise” )
Is the comment with the ";interpretation of the parenthesis" correct ? in SML , it was easy for me to “visualize” how the “append” function works, but here I don’t understand how to break that “cons” statement so I can visualize , piece by piece, like I would have a debugger with breakpoints in Eclipse
Could anybody please help me ?
the notes about what the parentheses are for look right, but I want to note that in many cases it’s not the parentheses that signify anything; it’s the symbol after the opening parenthesis, like define
or if
so (define ...)
is a definition and (if ...)
is a conditional and (car ...)
is a function call to the specific function car
, and that’s why parentheses are involved in so many different things
actually I think my confusion is because of the recursive call
In SML, I believe that particular example could be written as
if null xs
then ys
else hd xs :: myAppend (tl xs, ys)
(edit: code formatting)
@mihaidobri Here’s your my_append
, just with printing information at each iteration of the recursion: #lang racket
(define (lprintf l . args)
(apply printf (string-join l "\n") args))
(define (my_append xs ys)
(if (null? xs)
(begin
(lprintf '("xs is null"
"ys = ~a")
ys)
ys)
(begin
(lprintf '(""
" xs = ~a"
"(car xs) = ~a"
"(cdr xs) = ~a"
" ys = ~a"
"Press Enter")
xs (car xs) (cdr xs) ys)
(read-line)
(cons (car xs) (my_append (cdr xs) ys)))))
(my_append '(a b c) '(d e))
Run this code to see what happens at each step.
;START of the program
; 1) we pass '(1 2) '(8 9) as arguments to my_append
; 2) IF : xs is not null
; 3) So we get to line 7 with the cons .
; 4) here we "jump" straight to the most inner paranthesis , right? therefore we perform (cdr 1 2) -> '(2)
; 5) so now we call (my_append ('2) ('8 9)
; = but where is the element "1" ? in the stack?
;6) we are back in line 4 (define (my append xs ys)
;7) IF : 1 is not null
;) back in line 7 ) here we do again a recursive call ? and we "keep in mind that we have to do the cons function after all recursive calls are exausted ? but at this point xs will be null and the IF statement will give as "ys" list
this was the way I was “visualizing” the my_append
@laurent.orseau I will run your code , by the time I finished my above slack message, I noticed your message, so I will dive in
thank you! @laurent.orseau , @rokitna
indeed, SML is crystal clear for me, I can “see” what is happening, step by step
Is the “cons” done all together after we finish with all the recursive calls ? Or a “cons” function is called after each recursive call ?
@mihaidobri Let me introduce you to the “Algebraic Stepper”. It allows you to run programs one step at a time. It works for some of the teaching languages. So in the screenshot below, I have chosen “Beginning Student”. Modified you my_append
slightly and added a simple example. Then I clicked the “Step” button.
After clicking the “Step” button I now get this window:
Here I can go forward and backwards one step at a time.
I know you mentioned that the recursion was more confusing than the parentheses, but the following might be helpful: define my_append(xs, ys)
if null?(xs)
ys
else
cons(first(xs), my_append(tail(xs), ys))
end
end
Since Racket is not lazy, the recursive call to my_append
will complete, and then cons
will prepend the first element of xs to the result.
Thank you!
Thank you!
hey I am doing the same course in coursera, I also have a ML background, so instead of doing it like the slide, I wrote it closer to ML style (define (myappend xs ys)
(match xs
[(list) ys]
[(cons x tail) (cons x (myappend tail ys))]))
if you read (cons x tail)
as x :: xs
is essentially the same
@caente thank you ! this really helps
@soegaard2 Thank you again for introducing to me this incredible, awesome, extraordinary tool! This helps me so much to really visualise what is going on!
Hi Mike. Glad you liked it. It was written by @jbclements.
@jbclements BIG THANK YOU!
In the second >
I intentionally deleted the append
just to get used to the error messages. And to try to understand the meaning of “application”. So, my assumption is that "application" is nothing else than a “function call” . Is this right ? (for me also procedure = function)
Regarding the meaning of “application” , my understanding is that to apply a function or a operator, we must : 1) put it inside a pair of parentheses 2) where it should be followed by its arguments. For example, to add 2 and 3, we must write (+ 2 3) - were :"+" is a function
So in my screenshot , the error is just because I intentionally omitted to put a the “function” name ,e.g “append” .So if would have done this, like in my first " >
" example, the “function”(append) becomes an “application”. Is my understanding right ?
Yes, function application = function call
and correct, procedure = function
in the above screenshot, you attempt to use (list 1 2)
as a function, but it’s not. That’s why the error occurs.
I’m not sure what you mean by “function”(append) becomes an “application”.
(append (list 1 2) (list 3 4))
is a function application, with append
in the function position, and (list 1 2)
and (list 3 4)
in the argument positions.
To compare it with other languages:
print("abc")
is a function application, with print
in the function position, and "abc"
in the argument position.
@sorawee Thank you! the comparison helped me, inded, to understand what is this (function)application
Regarding “function”(append) becomes an “application”. I was trying to say that the function by itself named in this case “append” , will “become” or will “act” as function call , like in the this situation ( append (list 1 2) (list 34) )
I mean, in this case, “append” when placed inside ( ) , followed by proper arguments, will “act” as a function call / application .
like from a function it will “result” an application (although result is not the best name to describe this)
I don’t really follow, and I don’t think that’s how function application is described.
ok, so it means that I still have a misunderstanding somewhere. thank you for the feedback!
In a way I was trying to describe this behaviour
I would say append
is used in the function position of a function application.
But append
doesn’t become a function application
A function application is (append '(1 2) (3 4))
yes, correct
probably I was overthinking a little bit
@cdep.illabout_slack has joined the channel