Return multiple values from a function.

Started by netytan, December 06, 2005, 12:29:46 PM

Previous topic - Next topic

netytan

Hi guys,



I'm kinda new to Lisp in general so please forgive my ignorance here. I'm having a few problems with one function I'm writing, I can get it working by using append, and in theory i know what append does but i cant replicate this using (cons).



Somewhat annoying since it means i dont understand as much as i thought ;).



(define positive-binary
  (lambda (number)
  "This function simply returns a list containing the binary
  representation of number."
    (cons
      (if (= (remainder number 2) 0)
        0
        1)
      (if (= number 1) ()
        (positive-binary
            (truncate (/ number 2)))))))


Please don't tell me the answer but any hints would be great. As you might of guessed this isn't newlisp but is in fact Scheme. All I'm after here is to construct a list from the numbers returned with new numbers added to the beginning of the list, like a reverse append i guess ;).



when putting 10 into the function the result should be 1010 but right now I'm getting 0101. Its not a reversal problem :) am just putting things onto the wrong end of the list it seems.



Thank in advance guys,



Mark.

Lutz

#1
There is no fuction 'remainder' or 'truncate' in newLISP, use "%" or "mod" and 'floor' instead. The result of 'cons' will always be a list and 'cons' always adds the elements in front. Why not use 'append' it also works on strings and you can put the things to append in either order.



Lutz



Ps: if you insist on doing this in Scheme, you should put your questions in a Scheme users group.

eddier

#2
Since the digits are reverse order, try and change the order of the (if statements below the (cons



 (cons
    (if (= number 1)
      ()
    (positive-binary
...


Just a guess! There is also a xcons (reverse cons) function in the "srfi 1" library.



Eddie

netytan

#3
I'm not using NewLisp since Im required to do this in Scheme however this said general Lisp so i didnt think it would be a problem :). Very greatful for the fast reply, that really did suprise me.



When i reverse the order of them i get a list but its in reverse order. Maybe somone could produce an example append function so I can see how it works.



I don't want to use append because it requires another call to (list) and I'm trying to do this in the most efficient way I can :).


|(positive-binary 10)
| (positive-binary 5)
| |(positive-binary 2)
| | (positive-binary 1)
| | (() . 1)
| |((() . 1) . 0)
| (((() . 1) . 0) . 1)
|((((() . 1) . 0) . 1) . 0)


so what i need to do is put them at the end of the previous version of the list, in its CDR place, in effect sticking another cons on the end.



Thanks again guys,



Mark.

pjot

#4
I don't know Scheme. But this is how it works with newLisp:



#!/usr/bin/newlisp

(define (binary x)
"This function simply returns a list containing the binary representation of number."
(cons
(if (= (% x 2) 0)
0
1
)
(if (> x 1)
(binary (/ x 2))
'()
)
)
)

(println (reverse (binary 66)))
(exit)


Maybe it helps. Just convert it to Scheme.



Peter

netytan

#5
Hey pete :).



Thanks for the help, thats what I have working at the moment, using (reverse) but ideally i wanted to get it working inside the function, I guess I'm just not thinking recusively yet.



Will take a closer look and see if I can gain something here,



Thanks again.



Mark.

pjot

#6
OK this is an annoying problem indeed. I thought I had the solution but this was too hasty. Since I have nothing else to do:



#!/usr/bin/newlisp

(define (binary x)
"This function simply returns a list containing the binary representation of number."
  (flat
(cons
(if (> x 1)
(binary (>> x 1))
'()
)
(if (= (% x 2) 0)
0
1
)
)
)
)

(println (binary 66))
(exit)


This should work. You basically switch around the return values and flatten it out.



Peter

netytan

#7
Thanks a lot Peter, I can see how that works :). I've decided to go with the (reverse) method though, I think it'd be more effiencent in the long run :). If i do it like this way i'd be calling another functions repretedly, alternatively calling reverse once should do it :).



Ideally i could just put the CAR of the recursive value in the first part of the list and put the new value in CDR however it doesn't want to play that way.



Does anyone know of a better way to collect and return multiple values?



Thanks a lot!



Mark.

Sammo

#8
My two cents:



Mark wrote: "Ideally I could just put the CAR of the recursive value in the first part of the list and put the new value in CDR however it doesn't want to play that way."



In newLisp as well as Scheme, a reasonable approach is to write in the language you wish you had, and then implement that language. (I think that's a rough quote of something Fred Brooks wrote.)



The language element you're missing -- namely, (rcons a b) -> (b a) -- is readily implemented in newLisp.
(define (rcons a b)
  (reverse (cons a (reverse b))) )

With this function, you can write 'positive-binary' as you want to think about it. Following Peter's lead:
(define (positive-binary x)
  (rcons
    (if (= (% x 2) 0) 0 1)
    (if (<= x 1) '() (positive-binary (/ x 2))) ))

Examples:
Quote> (positive-binary 10)

(1 0 1 0)

> (positive-binary 0)

(0)

> (positive-binary 1)

(1)

> (positive-binary 66)

(1 0 0 0 0 1 0)

> (positive-binary 0x7FFF)

(1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)

netytan

#9
Thanks so much, thats just what I needed. However I was wondering if this would not better be implemented as a Macro, I'm not sure how NewLisps support for Macros is but Schemes really suck, it seems like very paper that talks about them and how to utilize them just doesn't work :(.



Just curious,



Thanks again :),



Mark.

netytan

#10
Oh, really liked the advice about how you should write in the language you wish you had :). Haven't heard it put quite like that.



Mark.

Lutz

#11
This one doesn't need to reverse things:

(define (binary x)
   (append
      (if (> x 1) (binary (/ x 2)) '())
      (if (= (% x 2) 0) '(0) '(1) )
   )
)

and it is really short ;)



Lutz

netytan

#12
Lol yes :) tried that code right at the beginning however Scheme is a little bitch in this sense and you have to make sure that what your trying to append is also a list it throws.



The one I'm using right now simply does a (cons) to collect all of the results in positive-binary; i imagine negative-binary will do the same. I have this nice little function which does a conditional function call and reverses the results before returning.



(define binary
  (lambda (number)
    "This function provides a simple generic front end to our
    positive/negative binary functions."
    (reverse
      ((if (> number 0)
        positive-binary
        negative-binary) number))))


As always please feel free to criticize I could really use any suggestions you guys could give while I'm getting to grips with Lisp :).



Very tidy in NewLisp. How does NewLisp compare for performance with Scheme and CL guys?

Lutz

#13
Even shorter!



(define (binary x)
   (append
      (if (> x 1) (binary (/ x 2)) '())
      (list (% x 2))
   )
)


Lutz



ps: didn't see your last post when I wroten this ;)

Fanda

#14
Slower and uglier, but shows a different way:


(define (log2 x)
  (div (log x) (log 2)))

(define (binary x)
  (let (mask 1 N (+ (log2 x) 1) result '())
    (dotimes (i N)
      (push (>> (& x mask) i) result)
      (setq mask (<< mask 1)))
    result))


Fanda



PS: This is what I remember from school ;-)