Functions w/o arguments

56 views
Skip to first unread message

Geoff Lane

unread,
Sep 6, 2008, 3:53:12 PM9/6/08
to study...@googlegroups.com
Working on the Hangman exercise in Chapter 6, I attempted to define a
function without any parameters.
I had defined a bunch of variables first thinking it would make the
program easier to understand. So, I really didn't need to pass
variables to the function

(define foo
(+ 4 5))

But (foo) gives:
function call: expected a defined name or a primitive operation name
after an open parenthesis, but found something else

Is this just not supported in the Beginning Student language?

I ended up just passing a defined variable to each function and used
it as a passed variable instead of a "global".
(foo DEF_COLOR)

--
Geoff Lane <ge...@zorched.net>

Geoffrey S. Knauth

unread,
Sep 6, 2008, 4:14:15 PM9/6/08
to study...@googlegroups.com
The syntax I would have used if I wanted a zero-argument function is:

(define (foo)
(+ 4 5))

but in Beginning Student language I get:

define: expected at least one argument name after the function name,
but found none

I tried all the languages from Beginning Student upward, and it wasn't
until Advanced Student that I could create a "thunk" -- a procedure
with zero arguments.

The syntax you used, (define foo (+ 4 5)), does not create a
function. It computes the sum of 4 and 5, namely 9, and binds the
symbol foo to that value. In a conventional language, the equivalent
of what you did is:

foo = 4 + 5;
foo(); // maybe John Lennon knows what function 9 is ("Number 9,
number 9, ....")

Geoff Lane

unread,
Sep 6, 2008, 4:24:43 PM9/6/08
to study...@googlegroups.com
On Sat, Sep 6, 2008 at 3:14 PM, Geoffrey S. Knauth <ge...@knauth.org> wrote:
>
> The syntax I would have used if I wanted a zero-argument function is:
>
> (define (foo)
> (+ 4 5))

Geoff's with a G of the world unite! :)

I guess I should have mentioned I tried that first, but it caused a
syntax error as you pointed out.

This is an interesting part about something like HTDP to me as a
non-beginner. It's in trying to "forget what you know" and only
program with the current tools you have. That exercise in constraint
based programming (where the constraints are the constructs you have
available) really makes you rethink some things.

Now I'm also curious what a true beginner feels as they go through
this and peel back the layers of the onion as more and more things are
exposed. It's just so different from how I learned - originally Basic,
Pascal and C++.

Thunk:
http://en.wikipedia.org/wiki/Thunk

--
Geoff Lane <ge...@zorched.net>

Barry Brown

unread,
Sep 6, 2008, 4:44:45 PM9/6/08
to study...@googlegroups.com
At the Beginning Student level, all functions must take at least one
argument and must return a value. It's a natural extension of
mathematical functions. For beginning students, we can build off what
you already know about math and extend that into the realm of
programming.

-B

Grant Rettke

unread,
Sep 6, 2008, 5:38:29 PM9/6/08
to Study-HTDP
On Sep 6, 3:14 pm, "Geoffrey S. Knauth" <ge...@knauth.org> wrote:
> The syntax I would have used if I wanted a zero-argument function is:
>
> (define (foo)
>    (+ 4 5))
>
> but in Beginning Student language I get:
>
> define: expected at least one argument name after the function name,  
> but found none

I think it expects either lambda or the argument list:

http://docs.plt-scheme.org/htdp-langs/beginner.html

Grant Rettke

unread,
Sep 6, 2008, 5:39:20 PM9/6/08
to Study-HTDP
On Sep 6, 3:44 pm, Barry Brown <ba...@cs.sierracollege.edu> wrote:
> At the Beginning Student level, all functions must take at least one  
> argument and must return a value. It's a natural extension of  
> mathematical functions. For beginning students, we can build off what  
> you already know about math and extend that into the realm of  
> programming.

Interesting, data-driven programming pervades the language...

Barry Brown

unread,
Sep 6, 2008, 6:34:17 PM9/6/08
to study...@googlegroups.com
I don't think that's a correct generalization. As Geoff Knauth pointed out, Scheme certainly supports zero-argument functions. But we're not here to learn Scheme; we're here to learn to be better computer scientists, which has little to do with language specifics.

So why are functions at this level required to take at least one argument? First of all, it would only occur to a "seasoned" programmer that a function could be any other way. Why write a function if all you wanted to do was a calculation?

But more deeply, let's start with some basic (if I may be so bold). Why write functions in the first place?


Here's a question: how many miles is 8000 feet? Easy, I'll just punch that into my calculator...
> (/ 8000 5280)
1.51515151

Here's another question: how many miles is 1543 feet? Well, that's easy, too. A quick calculation...
> (/ 1543 5280)
0.2922348

Both of those are questions. They have a single answer and when you've got the answer you're pretty much done with it.

But what happens if we generalize those questions into this: how many miles is ___ feet?
Now we've stated a problem. A problem doesn't have a single answer and can be turned into an infinite number of questions.

A problem is a large (or infinite) family of questions that share some features and differ in others. A program (or function) is a general rule for solving a problem with input(s) for the features that differ. You write programs/functions to solve problems. Problems, by definition, encapsulate a large number of questions by using inputs to drive the computation.

Don't waste your time writing functions to answer questions; write them to solve problems.

-B

P.S. If you really want to assign a name to the answer to a question, here's how you do it:
(define foo (/ 1543 5280))

Now "foo" always has the value .2922348 and you can use it in any expression that takes a number as an argument.

Geoffrey Lane

unread,
Sep 6, 2008, 7:33:23 PM9/6/08
to study...@googlegroups.com
!!! Spoiler Alert !!! If you don't want to see discussion of chapter 6 yet - skip this.





Thanks for the great response.

I was specifically working on the Hangman program in Chapter 6.

This seems to want to encapsulate an algorithm that is really just a series of defined steps. This is not so much of a problem statement. Basically drawing lines and shapes. There is a relationship among the positions of the elements in a stick figure. For example, the body extends from the bottom of the circle that is the head and the legs extend from the bottom point of the body.

I started with the form of a series of functions assuming that the positions of the drawn elements would be fixed, so I came up with:

(define (draw-noose)...)
(define (draw-head)...)
(define (draw-body)...)

I then decided to calculate the values to define where each element would be positioned on the screen:
(define BAR_END (make-posn 100 10))
(define ROPE_END (make-posn (posn-x BAR_END) (+ (posn-y BAR_END) 20)))

(define HEAD_CENTER (make-posn (posn-x ROPE_END) 40))
(define HEAD_RADIUS (- (posn-y HEAD_CENTER) (posn-y ROPE_END)))

So, it just felt unnatural to pass arguments to those functions. Even without those pre-calculated positions, I would have just had to hard-code values in the function itself. In the end it seemed to overly complicate things to have to pass arguments to those functions.

So, I'm curious how other people will implement this.

Geoffrey S. Knauth

unread,
Sep 6, 2008, 8:10:31 PM9/6/08
to study...@googlegroups.com
On Sep 6, 2008, at 18:34, Barry Brown wrote:

A problem is a large (or infinite) family of questions that share some features and differ in others. A program (or function) is a general rule for solving a problem with input(s) for the features that differ. You write programs/functions to solve problems. Problems, by definition, encapsulate a large number of questions by using inputs to drive the computation.

This semester I'm teaching a class (using the Patterson & Hennesy text) that has a lot of assembly language.  On Friday I was explaining the nitty gritty of single- and double-precision floating point.  For example, in single-precision floating point, you have one sign bit, 8 bits of exponent with an assumed -127 offset, and 23 fraction bits with an assumed 1 added to it.  All those bits and assumptions are a headache for humans, so we made lists of bit patterns and wrote some functions to decode the pieces, a bit like this:

value = (-1)^sign * (1 + fraction_bits) * 2^(exponent_bits - 127)
or
(* (expt -1 sign) (add1 fraction) (expt 2 exponent))

Our test data looked like this:

(define p_2^128   '((0) (1 1 1 1 1 1 1 1) (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)))
(define n_0_75    '((1) (0 1 1 1 1 1 1 0) (1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)))
(define p_15k     '((0) (1 0 0 0 1 1 0 0) (1 1 0 1 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0)))
(define mystery   '((0) (0 1 1 1 1 1 0 1) (0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 1 0)))
(define p_14_75   '((0) (1 0 0 0 0 0 1 0) (1 1 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)))
(define n_0_6875  '((1) (0 1 1 1 1 1 1 0) (0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)))
(define p_12_5625 '((1) (1 0 0 0 0 0 1 0) (1 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)))
(define p_12      '((0) (1 0 0 0 0 0 1 0) (1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)))
(define n_8_5     '((1) (1 0 0 0 0 0 1 0) (0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)))
(define p_0_3125  '((0) (0 1 1 1 1 1 0 1) (0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)))

Once we went over the functions to decode bit patterns, the class lost its fear of floating point, and even gained some insight into where floating point errors come from.

(fp->normal mystery)
;-> 5033165/16777216
(exact->inexact (fp->normal mystery))
;-> 0.30000001192092896

mystery is .3, or as close to .3 as you're going to get with digits of precision promised by single-precision.

Having functions to solve problems gave us the freedom to try out lots of experiments like this.



Grant Rettke

unread,
Sep 7, 2008, 3:44:19 AM9/7/08
to Study-HTDP
>> Interesting, data-driven programming pervades the language...
> I don't think that's a correct generalization. As Geoff Knauth pointed  
> out, Scheme certainly supports zero-argument functions. But we're not  
> here to learn Scheme; we're here to learn to be better computer  
> scientists, which has little to do with language specifics.

I was only referring to the Beginning Student language, not Scheme in
general. Something like "Something must go in because something must
come out!"; which you captured so eloquently in your post!

Grant Rettke

unread,
Sep 7, 2008, 3:45:25 AM9/7/08
to Study-HTDP
On Sep 6, 7:10 pm, "Geoffrey S. Knauth" <ge...@knauth.org> wrote:

> Having functions to solve problems gave us the freedom to try out lots  
> of experiments like this.

I'm taking notes...

Veer

unread,
Sep 7, 2008, 7:35:29 AM9/7/08
to Study-HTDP
You can define the drawing components in terms of other drawing
components .
Something like this :

(define NOOSE (make-noose LINE1 LINE2 CIRCLE)

(define HEAD-RADIUS (/ NOOSE-RADIUS 4))
(define HEAD-CENTER (find-center HEAD-RADIUS POINT-ON-CIRCLE ))
(define HEAD (make-circle HEAD-CENTER HEAD-RADIUS 'black))

(define BODY-LENGTH ..)
(define BODY-START ...)
(define BODY-END ..)
(define BODY (make-line BODY-START BODY-END))

and so on.
This way you can pass the the arguments if needed or draw there
itself.
Any changes in NOOSE will automatically reflect in other components/
definitions.

Barry Brown

unread,
Sep 8, 2008, 12:29:18 AM9/8/08
to study...@googlegroups.com
Exactly! It's the "conservation of data" law that governs computing.
:)

Kartik

unread,
Oct 7, 2008, 11:24:40 PM10/7/08
to study...@googlegroups.com
!!! Spoiler Alert!!! If you don't want to see discussion of chapter 6 yet - skip this.


Hi Geoff,

I thought I would share my solution with you.  I did take the route of passing arguments to the various draw functions.  I was a little uncomfortable seeing the draw functions referring to globals.  So here's what I came out with.

;; structures
(define-struct hangman-board (origin width height hangpost noose))
(define-struct hangpost (width hook-height color))
(define-struct noose (origin radius color))
(define-struct person (height color))

;; functions
(define (draw-hangman-board hangman-board) ...)
(define (draw-hangpost origin hangpost) ...)
(define (draw-next-part part) ...)
(define (draw-noose noose) ...)
(define (draw-head origin person) ...)
(define (draw-body origin person) ...)
....

Here is how I get the whole thing rolling:
(define HANGMAN-BOARD (make-hangman-board (make-posn 0 10)
                                          300
                                          300
                                          (make-hangpost 150 50 'blue)
                                          (make-noose (make-posn 150 80) 30 'green)))
(define PERSON (make-person 150 'black))
(start (hangman-board-width HANGMAN-BOARD)
       (hangman-board-height HANGMAN-BOARD))
(draw-hangman-board HANGMAN-BOARD)

The only clumsy part is (draw-next-part) where I refer to the global HANGMAN-BOARD.  I kept the signature intact because that was a requirement in the exercise.  I passed Person to draw-head, draw-body etc. functions because I wanted the dimensions of face, arms etc. to be proportional to the height.  I still haven't got all parts completely proportional but it is good enough for now.


Reply all
Reply to author
Forward
0 new messages