Function call: error

i am following this tutorial from the I Fixed-Size Data and i copied and pasted this code

(define current-color "amber")

(define next-color
  (if (string=? "green" current-color) next-color "yellow" ))

and when i run it i get this error

(current-color "red")
function call: expected a function after the open parenthesis, but found a variable

The expression (current-color "red") seems like it's trying to apply a function, but current-color is a string, not a function. That's why it doesn't work.

1 Like

as @samth says, current-color here is not a function, but it seems like parameter usage. So maybe you would like to define current-color like the following:

(define current-color (make-parameter "amber"))

From the link, I think @osman44 is working through HtDP so it's unlikely they really want a parameter.

2 Likes

its still not working what should i do (define color "amber")

(define next-color
(if (string=? "green" color) "yellow" color))

(next-color "green")
. . application: not a procedure;
expected a procedure that can be applied to arguments
given: "amber"

You're running into the difference between declaring a function and declaring a variable.

  • (define next-color "green") creates a variable named 'next-color' and assigns it the value "green", which is a string
  • (define next-color (lambda (c) "green") creates a variable named 'next-color' and assigns it the value (lambda (c) "green"), which is a function that returns the string "green"
  • (define (next-color c) "green") is a shortcut for the function-creation version immediately above. It is the most common way to create functions in Racket.

(See footnote [1])

Doing this: (next-color "green") means that you want to call the function next-color with the argument "green" and have it return the result.

Doing this: next-color means that you want to put the string "green" at that location in your program's execution.

You have defined next-color to be a variable but you are using it as a function. Don't do that.

I'm assuming that you want to define a variable the value of which is determined by the if statement, then later change the value of that variable to be "green". The correct syntax for that would be:

(define color "amber")
(define next-color (if (string=? "green" color) "yellow" color)) ; create the variable, assign it
(set! next-color "green") ; change the contents of the variable

That will work, but it's not very Rackety. Racket is a functional programming language, meaning that values do not change once they are created. If you want to have a new value, you create a new variable. set! is a mutation operator, and Racket wants to avoid mutation because programs are easier to understand and less bug-prone when they do not use mutation. It means that everyone involved can look at the contents of a variable and rely on those contents always staying the same.

There are a lot of Rackety ways to do this depending on what you're trying to accomplish. One way would be to use a parameter, like so:

; This is the naive version that you should not use
(define next-color (make-parameter "amber")) ; a parameter is a special kind of function that holds a value

(next-color) ; used with no arguments, evaluating the parameter will return its contents, in this case the string "amber"

(next-color "green") ; used with an argument, the parameter's value is updated to the new value

(next-color) ; this time it will return the string "green"

This does what you were looking for but it should be avoided because it's effectively mutating the value and that mutation will be visible from every part of your program that uses the parameter. A better way to do it is this:

; This is the right way to use a parameter
(define next-color (make-parameter "amber"))

(next-color) ; returns "amber"

(parameterize ([next-color "green"]) ; creates a new scope, changes the contents of the parameter within that scope, automatically reverts the contents after you leave the scope
  (next-color) ; returns "green"
) ; closes the 'parameterize', reverts the parameter's contents

(next-color)  ; returns "amber"

Parameters are a bit heavyweight. Here's a simpler method:

(define next-color "amber")
(let ([next-color "green"])  ; creates a new scope.  creates a new variable within this scope.  the new variable is named 'next-color' but it is not the same 'next-color' that was defined above
  (display next-color) ; prints the string "green" to the screen
) ; closes the 'let', gets rid of the 'next-color' variable that was created for it

(display next-color) ; prints the string "amber" to the screen because we are back to the scope outer scope where (define next-color "green") was used

Does that help?


[1] Instead of saying that a value is assigned to a variable, Racket says that a value is bound to an identifier. I'm using variable and assign because I suspect they will be more familiar. The difference is not worth going into here.