Functions and their "return" values

Started by dukester, September 17, 2009, 08:34:55 PM

Previous topic - Next topic

dukester

I want to port a Perl function that does the following:


sub some_function {
declare a local_var
if (some_test) { do something
return local_var}

if (some_other_test) { return something}
else {return 0}
}


So I've come up with:


(define (my_func)
(local (my_var)
(if (= "blah" my_var) (do this))
return_something
    )
(if (= "blaah" some_var) (return_something_else))

(if none of the above are true (return nil))
)

I'm kinda stuck on returning different values depending on the outcome of the "if" statements.  I'm getting mixed up with the syntax for functions with that of "if" statements. Any advice?



Being used to imperative languages, I'm finding a functional language a bit of a challenge --- but fun! TIA..
duke

cormullion

#1
In newLISP (almost) every expression returns a value when evaluated, so think of the two parentheses enclosing an expression as 'collapsing together' to produce a single value:


(if (= 2 2) "yes" "no")

- the if is a function and returns a  value, either "yes" or "no" in this case:


> (set 'x (if (= y 2) "yes" "no"))
"no"
> (set 'y 2)
2
> (set 'x (if (= y 2) "yes" "no"))
"yes"


A user-defined function also returns a single value when evaluated:


(define (action1)
   "this is action 1")
   
(define (my-func)
  (local (x)
     (if (= blah 2)
         (action1))))

(set 'blah 2)
(my-func)
;-> "this is action 1"


In this definition of my-func, the value returned by the function is the value of the last evaluation. Here, it's the string returned by the last evaluation in the function action1.



Getting closer to your Perl: you might find it helpful to use a more Lisp-y construct, such as cond.


(define (my-func a)
   (cond
      ((= a "blah")    1)
      ((= a "blip")    -1)
      (true            0)))
     
(my-func "blah")
;-> 1
(my-func "blab")
;-> 0
(my-func)
;-> 0


Notice how the '1' is returned by the cond, then returned in turn by the my-func. The "true" clause is the "if nothing else" bit; it's the last evaluation of the function, so the function returns 0 if nothing else matches.



The advantage of cond is that you can easily do two or more actions for each 'case':


(define (my-func a)
   (cond
      ((= a "blah")    (println "'we have a blah'")
                       (set 'self-destruct 'yes))
     
      ((= a "blip")    (println "'we have a blip'")
                       (set 'self-destruct 'cancel))
 
      (true            (println "'we got nothing'")
                         0)))
> (my-func "blah")
'we have a blah'
yes
> (my-func "blip")
'we have a blip'
cancel
> (my-func "")
'we got nothing'
0
>


Sometimes you can't organize your code to make this work. So you have to remember to return the symbol as the last action of the function:


(define (my-func a)
  (let ((self-destruct 'cancel))
   (cond
      ((= a "blah")    (set 'self-destruct 'yes))
     
      ((= a "blip")    (set 'self-destruct 'cancel))
     
      (true            (println "it's all gone wrong")))
     
  self-destruct))


What's harder to do in newLISP is your idea of explicitly returning from different places in a function. Use the built-in branching provided by if, cond, etc...



I'm writing too much - stop me!

dukester

#2
Thanks for the mini-tutorial!



It just dawned on me that I haven't consciously been thinking of the "if" construct as a function -- but it is! I have to become _more_ conscious that most things in *LISP is a function.



Another thing that is "overloading" me at the moment, is the multitude of ways to "declare" a symbol (variable). eg.



(set 'x "zero")

(define x1 "one")

(setf x2 "two")

(setq x3 "three")



Also, the choice of using "local" in a user-defined function , or including the symbols as arguments to the function.



I would like to settle on one way to declare a symbol and to "localize" them to a function when necessary. Which would you choose if you had to pick one of each?



Otherwise, it's simply "information overload", for a *LISP novice. ;(



Thanks again!
duke

cormullion

#3
newLISP is "pragmatic and casual", so choose the style you feel most comfortable with, if it works! The reference manual will enlighten you as to the differences between them. I like to use define to set context variables, set for most other purposes, and setf when I have to use it for setting list and array references.

dukester

#4
I've just about settled on using:



"set" for most symbols

"define" for functions only



I'll find out soon enough if tis personal protocol will work for most cases. Of course, "setf" appears to be a special case.



What about "local" variables? I'm leaning toward including them in the argument list, as opposed to using the "local" function.
duke

Kazimir Majorinc

#5
Usually programmer needs to initialize, not only declare local variable, so
http://kazimirmajorinc.com/\">WWW site; http://kazimirmajorinc.blogspot.com\">blog.

TedWalther

#6

(constant '≠ !=)     # 2260 not equal
(constant '∈ find)   # 2208 element of
(constant '≤ <=)     # 2264 less than or equal
(constant '≥ >=)     # 2265 greater than or equal
(constant '∀ dolist) # 2200 for all
(constant '← setq)      # 2190 assignment
(constant '∑ add)    # 2211 n-ary summation
(constant '× mul)    # 00d7 multiply
(constant '÷ div)    # 00f7 divide
(constant '⌈ ceil)   # 2308
(constant '⌊ floor)  # 230a
(constant '∨ or)     # 2228
(constant '∧ and)    # 2227

(if (≠ 1 2) (println "1 ≠ 2"))
(if (∈ 1 '(3 2 1)) (println "1 ∈ (3 2 1)"))
(∀ (x '(1 2 3)) (println x))
Cavemen in bearskins invaded the ivory towers of Artificial Intelligence.  Nine months later, they left with a baby named newLISP.  The women of the ivory towers wept and wailed.  \"Abomination!\" they cried.