In Racket, it's possible to return multiple values from a function by doing e.g.
(define (foo)
(values 1 2 3))
Then we can bind them by doing
(define-values (one two three) (foo))
Now one is bound to 1, two to 2, and three to 3.
I have a function that returns multiple values, but I'm interested only in some of them. Is there a way of extracting the "interesting" return values, while "ignoring" (i.e. not binding) the rest, a la _ pattern in Haskell?
You can use match-let-values or match-define-values for this (depending on whether you want lexical or top-level variables):
> (match-let-values (((_ _ a _) (values 1 2 3 4)))
a)
; => 3
> (match-define-values (_ a _ _) (values 1 2 3 4))
> a
; => 2
Related
Often, I have main functions that run multiple functions in my common lisp apps.
(main
(run-function-1...)
(run-function-2...)
(run-function-3...)
(run-function-4...)
(run-function-5...))
At the moment, I have this situation where each function in main returns a varying number of values. However, the number of return values are also fixed.
I want main to return all values from all function.
(main
(run-function-1...) ;<--- returns 2 values
(run-function-2...) ;<--- returns 2 values
(run-function-3...) ;<--- returns 1 values
(run-function-4...) ;<--- returns 3 values
(run-function-5...)) ;<--- returns 2 values
;; main should return 10 values
When I do multiple-value-bind inside of main it doesnt capture all function returns. Because it only accepts one value-form.
You could use multiple-value-list + append + values-list, but I think the most straightforward is multiple-value-call:
(multiple-value-call #'values
(run-function-1 ...)
(run-function-2 ...)
(run-function-3 ...)
(run-function-4 ...)
(run-function-5 ...))
If you want to return a list, replace #'values with #'list.
You have to repack the returned values into a new values call:
(defun run-function-1 ()
(values 1 2))
(defun run-function-2 ()
(values 3 4 5))
(defun main ()
(multiple-value-bind (a b) (run-function-1)
(multiple-value-bind (c d e) (run-function-2)
(values a b c d e))))
(main)
1 ;
2 ;
3 ;
4 ;
5
I'm trying to solve this problem:
Define a function
blendList : 'a list * 'a list -> 'a list
that takes two lists and returns one list containing a "blend" of the two lists with values selected in strict alternation from the two lists. Do not use any built-in Standard ML functions other than length.
Some examples:
blendList([1,2], [100,200,300,400]) (* Returns [ 1 ,100,2 ,200,300,400] *)
blendList([200,100,300,900], [3,1]) (* Returns [ 200 ,3,100 ,1,300,900] *)
blendList([],[100,200]) (* Returns [100,200] *)
blendList([1,2],[]) (* Returns [1,2] *)
How do I do this?
Please consider the following code:
fun blendList ([], l) = l
| blendList(l, []) = l
| blendList(a :: restA, b :: restB) = a :: b :: blendList(restA, restB);
blendList([1,2], [100,200,300,400]); (* Returns [ 1 ,100,2 ,200,300,400] *)
blendList([200,100,300,900], [3,1]); (* Returns [ 200 ,3,100 ,1,300,900] *)
blendList([],[100,200]); (* Returns [100,200] *)
blendList([1,2],[]); (* Returns [1,2] *)
blendList([1,2],[1,2]); (* Returns [1,1,2,2] *)
We split the blendList into 3 options:
The first list is empty.
The second list is empty.
Both have entries.
In the first option, we take the second list. in the second option, we take the first list. In the last one, we take both of the first elements, and activating the same method again, with what is left.
Note, that if both lists are of the same size, it will get to the last call blendList[[], []], which will fall into the first case, and return [].
I have the following question "Given a list of integer pairs, write a function to return a list of even numbers in that list in sml".
this is what I've achieved so far
val x = [(6, 2), (3, 4), (5, 6), (7, 8), (9, 10)];
fun isEven(num : int) =
if num mod 2 = 0 then num else 0;
fun evenNumbers(list : (int * int) list) =
if null list then [] else
if isEven(#1 (hd list)) <> 0
then if isEven(#2 (hd list)) <> 0
then #1 (hd list) :: #1 (hd list) :: evenNumbers(tl list)
else []
else if isEven(#2 (hd list)) <> 0
then #1 (hd list) :: evenNumbers(tl list)
else [];
evenNumbers(x);
the result should be like this [6,2,4,6,8,10]
any help would be appreciated.
I see two obvious problems.
If both the first and second number are even, you do
#1 (hd list) :: #1 (hd list) :: evenNumbers(tl list)
which adds the first number twice and ignores the second.
If the first number is odd and the second even, you do
#1 (hd list) :: evenNumbers(tl list)
which adds the number that you know is odd and ignores the one you know is even.
Programming with selectors and conditionals gets complicated very quickly (as you've noticed).
With pattern matching, you could write
fun evenNumbers [] = []
| evenNumber ((x,y)::xys) = ...
and reduce the risk of using the wrong selector.
However, this still makes for complicated logic, and there is a better way.
Consider the simpler problem of filtering the odd numbers out of a list of numbers, not pairs.
If you transform the input into such a list, you only need to solve that simpler problem (and there's a fair chance that you've already solved something very similar in a previous exercise).
Exercise: implement this transformation. Its type will be ('a * 'a) list -> 'a list.
Also, your isEven is more useful if it produces a truth value (if you ask someone, "is 36 even?", "36" is a very strange answer).
fun isEven x = x mod 2 = 0
Now, evenNumbers can be implemented as "just" a combination of other, more general, functions.
So running your current code,
- evenNumbers [(6, 2), (3, 4), (5, 6), (7, 8), (9, 10)];
val it = [6,6,3,5,7,9] : int list
suggests that you're not catching all even numbers, and that you're catching some odd numbers.
The function isEven sounds very much like you want to have the type int -> bool like so:
fun isEven n =
n mod 2 = 0
Instead of addressing the logic error of your current solution, I would like to propose a syntactically much simpler approach which is to use pattern matching and fewer explicit type annotations. One basis for such a solution could look like:
fun evenNumbers [] = ...
| evenNumbers ((x,y)::pairs) = ...
Using pattern matching is an alternative to if-then-else: the [] pattern is equivalent to if null list ... and the (x,y)::pairs pattern matches when the input list is non-empty (holds at least one element, being (x,y). At the same time, it deconstructs this one element into its parts, x and y. So in the second function body you can express isEven x and isEven y.
As there is a total of four combinations of whether x and y are even or not, this could easily end up with a similarly complicated nest of if-then-else's. For this I might do either one of two things:
Use case-of (and call evenNumbers recursively on pairs):
fun evenNumbers [] = ...
| evenNumbers ((x,y)::pairs) =
case (isEven x, isEven y) of
... => ...
| ... => ...
Flatten the list of pairs into a list of integers and filter it:
fun flatten [] = ...
| flatten ((x,y)::pairs) = ...
val evenNumbers pairs = ...
Here is a simplified version of my problem: Generate a list of random values in which each consecutive value depends on the previous one.
For example, generate a list of random Int, in which each consecutive value will establish minimum for the next step. Let's assume that starting value = 0 and maximum value is always currentValue + 5 :
First step: Random.int 0 5 => 3
Next: Random.int 3 8 => 4
Next: Random.int 4 9 => 8
etc.
Here is my approach:
intGen : Int -> List (Rnd.Generator Int) -> List (Rnd.Generator Int)
intGen value list =
if length list == 10 then
list
else
let newValue = Rnd.int value (value + 5)
newList = newValue :: list
in intGen newValue newList
Let's transform it into Rnd.Generator (List Int):
listToGen : List (Rnd.Generator Int) -> Rnd.Generator (List Int)
listToGen list =
foldr
(Rnd.map2 (::))
(Rnd.list 0 (Rnd.int 0 1))
list
I don't like this part: (Rnd.list 0 (Rnd.int 0 1)). It generates initial value of type Rnd.Generator (List Int), in which (Rnd.int 0 1) is actually never used but is needed by type checking. I would like to skip this part somehow or replace it with something more generic. Is it possible or my implementation is erroneous?
Here is one solution which uses andThen and map. The first parameters is the number of elements you want in the list. The second parameter is the starting value.
intGen : Int -> Int -> Rnd.Generator (List Int)
intGen num value =
if num <= 0 then
constant []
else
Rnd.int value (value + 5)
|> Rnd.andThen (\i -> intGen (num-1) i
|> Rnd.map (\rest -> i :: rest))
To match your example of a list of size 10 starting with 0 as the first low value, you would call this as intGen 10 0.
constant is a generator from elm-community/random-extra, or it can be defined simply like this (because it isn't exposed in the core Elm codebase):
constant : a -> Rnd.Generator a
constant a = Rnd.map (\_ -> a) (Rnd.int 0 1)
Regarding your example, I don't think you would want to use List (Rnd.Generator Int) because that implies a list of generators that aren't tied together in any way. That's why we need to use andThen to pull out the random value just generated, call intGen recursively minus one, then use map to put the list together.
Using Common Lisp I am trying loop through a list of students and if the GPA is greater than or equal to 3.0 I want to push a 1 onto another list called equal_names. The problem I am having is the interpreter keeps saying the GPA in the comparison list is "not of type (or rational float)". Why am I getting this error?
Yes, this is for homework. Also this is my first time asking on here, so if you need anything else please let me know.
Sample of the list I am getting the GPA from, where the GPA is 2.307...:
(SETQ students (LIST
(LIST (LIST 'Abbott 'Ashley 'J) '8697387888 'NONE 2.3073320999676614)))
The code I have written:
(setq gpa_count ())
(loop for x in students
if(>= 3.0 (cdr (cdr (cdr x))))
do(push '1 gpa_count))
Given a non-empty list cdr returns the tail of that list, i.e. the list that contains all the elements of the list but the first. The important thing to note is that it returns a list, not an element. That is (cdr (cdr (cdr x))) returns the list (2.30733...), not the float 2.30733.
The loop iterates the outer list. To understand the code in the loop you can look at the first element in students, which is:
'((Abbott Ashley J) 8697387888 NONE 2.3073320999676614)
Now we are going to orientate the list. Every time you pass an element add a d.
Every time you pick a value or go to a list in the list you add an a.
To find how to access the number 2.307.... You look at the first element element in the list:
(Abbott Ashley J) d
8697387888 d
NONE d
Now we are at the part that you are interested in, ie. (2.3073320999676614)), thus you add an a. Now order those in reverse and put a c in front and a r in the end.. It becomes cadddr In light of that your loop should be:
(setq students '(("Mary Larson" 333 NONE 1.1)
("Mina Morson" 333 NONE 2.5)
("Magnus Outsider" 333 NONE 4.1)))
(setq gpa_count ())
(loop for x in students
if (>= 3.0 (cadddr x))
do (push '1 gpa_count))
gpa_count ; ==> (1 1)
Another example:
(setq x (1 (2 3) (3 4 (5 6) 7))) ; ==> (1 (2 3) (3 4 (5 6) 7))
To get the 3*. We follow the parts. 1 == d, (2 3) == a, 2 ==d, 3* == a. In reverse: adad and add c and r to the ends ==> cadadr. thus:
(cadadr '(1 (2 3) (3 4 (5 6) 7))) ; ==> 3
To get the 5. we do the same 1 == d, (2 3) == d and then we have the list we want ==a.
Then 3 ==d, 4 ==d, (5 6) ==a. The 5 is the first element == a. In reverse aaddadd. Now CL guarantees 4 letters accessors so we need to split it up in 4s from the right. Thus it becomes:
(caadr (cdaddr '(1 (2 3) (3 4 (5 6) 7)))) ; ==> 5
Now, without describing you can pick any number or list. Eg. to get (5 6) ddadda, in reverse and split up becomes (cadr (cdaddr x))
Hope it helps.
If your data format is consistent then
(fourth x)
will return the GPA.
Going further,
(setf (symbol-function 'gpa)(function fourth))
would provide
(gpa x)
as "an accessor" for the gpa in the data structure.
My CLISP 2.49 gives this error message:
*** - >=: (2.307332) is not a real number
Let's look at that error message: >=: (2.307332) is not a real number.
The error happens at the call to >= and one argument is a list of a number, not a number.
Since you try to extract the number from a list, does that extract work?
We see that you call CDR. CDR of a list returns a list. So there is the error. You need to extract the number from the list.
Btw., CLISP has commands like help, where, backtrace, ... to further investigate the problem. Just type help and return, without anything else, and you see a list of commands.