Pass a list as a parameter function?
I am trying to make a simple function in a schema that finds the largest number in a list.
Here is my code:
(define (maximo lista maximo_actual)
(if (= lista ())
maximo_actual
(let* ((primero maximo_actual)
(segundo (car lista)))
(if (> primero segundo)
((maximo (cdr lista) primero))
((maximo (cdr lista) segundo))))))
I am calling the function like this:
(maximo (list 6 3 2 8 9) 5)
And the program will return this:
;ERROR: "programas.scm": =: Wrong type in arg1 (6 3 2 8 9)
; in expression: (#@= #@lista ())
; in scope:
; (lista maximo_actual) procedure maximo
; defined by load: "programas.scm"
I think there is something wrong with the parameters. I am researching the circuit and I don't know where the problem is.
source to share
My tent here is Racket based (which is schematic based)
There are several problems with your program. One, =
compares numbers, not lists. Second, it ()
is a function that has nothing, not a list. To create an empty list, use either (list)
or '()
. Finally, it ((maximo (cdr lista) primero))
has an additional set of parentheses that cause the result to be executed (maximo (cdr lista) primero)
. However, the result (maximo (cdr lista) primero)
is a number.
I think you need something like this which will return 9
when you call(maximo (list 6 3 2 8 9) 5)
(define (maximo lista maximo_actual)
(if (empty? lista)
maximo_actual
(let* ((primero maximo_actual)
(segundo (car lista)))
(if ( > primero segundo)
(maximo (cdr lista) primero)
(maximo (cdr lista) segundo)))))
You can also write it with fold , which is a little shorter:
(define (maxio2 current result)
(if (> current result)
current
result))
(foldl maxio2 5 (list 6 3 2 8 9))
source to share
I have four points in your function:
- Your error is because the operator
=
is for numerical comparison, not general equality. To check that a list is empty, you usually use a functionnull?
. - Also, type expression is
if ... then ... else if ...
usually usedcond
instead ofif
. - You don't need to here
let*
; unstablelet
. In fact, I will do without bindingslet
for this simple function. - You really need to use regular Lisp indentation and copy the parentheses.
So your function with these changes:
(define (máximo lista máximo-actual)
(cond ((null? lista)
máximo-actual)
((> (car lista) máximo-actual)
(máximo (cdr lista) (car lista)))
(else
(máximo (cdr lista) máximo-actual))))
A more advanced way of writing this function is to use the fold-left
generic iterative list operator, which we can define as follows:
(define (fold-left función valor-corriente lista)
(if (null? lista)
valor-corriente
(fold-left función
(función (car lista) valor-corriente)
(cdr lista))))
fold-left
matches this common for
-loop type in imperative languages:
resultado = valor_inicial
for valor in valores:
resultado = función(valor, resultado)
return resultado
Using the fold-left
second helper function as well máximo-de-dos-valores
, we now have:
(define (máximo lista máximo-inicial)
(fold-left máximo-de-dos-valores máximo-inicial lista))
(define (máximo-de-dos-valores a b)
(if (> a b)
a
b))
source to share
This is a more idiomatic Scheme procedure for finding the maximum value in a list:
(define (mi-maximo lista)
(if (empty? lista)
null
(maximo (rest lista) (first lista))))
(define (maximo lista maximo-actual)
(cond ((empty? lista) maximo-actual)
((> (first lista) maximo-actual)
(maximo (rest lista) (first lista)))
(else (maximo (rest lista) maximo-actual))))
Note that I have introduced a new procedure mi-maximo
to call a helper procedure maximo
that does all the work. For those cases where you have more than two conditions, it is better to use cond
a series of nested ones instead if
. Finally, it prefers to use empty?
or null?
for testing if the list is empty. Use the above procedures:
(mi-maximo '(1 2 3 4 5))
> 5
As a final note, a style comment: in Scheme (and other LISPs, for that matter), you close all the parentheses on one line, not on separate lines. They are not curly braces, you know :)
source to share