3.5. Sequence Group section says
Elements enclosed in parentheses are treated as a single element,
whose contents are strictly ordered. Thus,
elem (foo / bar) blat
matches (elem foo blat) or (elem bar blat), and
Given exactly one element is allowed what exact payload does the "strictly ordered" part carry?
The sequence group (a b c) is just for grouping the given elements. This is used for repetitions
like
*(a b c)
The entries inside the sequence group must appear in the given order. Then the sequence group itself can appear/match based on other operators (like the * operator above).
The example shown in 3.5 Sequence Group is only for shown the issue between
elem (foo / bar) blat
and
elem foo / bar blat
that the () is needed when you want a matching of elem foo blat or elem bar blat.
Related
I am experimenting with clojure's lazy sequences. In order to see when the evaluation of an item would occur, I created a function called square that prints the result before returning it. I then apply this function to a vector using map.
(defn square [x]
(let [result (* x x)]
(println "printing " result)
result))
(def s (map square [1 2 3 4 5])) ; outputs nothing
Here in my declaration of s, the REPL does not output anything. This signals that the computation has not started yet. This appears to be correct. I then do:
(first s)
The function "first" takes only the first item. So I expect that only 1 will be evaluated. My expectation is the REPL will output the following:
printing 1
1
However, the REPL outputted the following instead.
printing 1
printing 4
printing 9
printing 16
printing 25
1
So rather than evaluating only the first item, it seems it evaluates all items, even though I am accessing just the first item.
If the state of a lazy sequence can only be either all values computed and no values computed, then how can it gain the advantages of lazy evaluation? I came from a scheme background and I was expecting more like the behavior of streams. Looks like I am mistaken. Can anyone explain what is going on?
Laziness isn't all-or-nothing, but some implementations of seq operate on 'chunks' of the input sequence (see here for an explanation). This is the case for vector which you can test for with chunked-seq?:
(chunked-seq? (seq [1 2 3 4 5]))
When given a collection map checks to see if the underlying sequence is chunked, and if so evaluates the result on a per-chunk basis instead of an element at a time.
The chunk size is usually 32 so you can see this behaviour by comparing the result of
(first (map square (vec (range 35))))
This should only display a message for the first 32 items and not the entire sequence.
why does hd dates become the oldest one? I just cannot figure out the process
fun oldest(dates : (int * int * int) list) =
if null dates
then NONE
else
let
val d = oldest(tl dates)
in
if isSome d andalso is_older(valOf d, hd dates)
then d
else SOME(hd dates)
end
In my opinion, this is much easier to understand with a small helper function and case analysis by pattern matching.
(My advice is to get comfortable with patterns and case analysis, avoiding conditionals and selector functions. It's much easier to reason about one thing at a time than to remember a whole chain of logic and destructuring.)
Rewriting your code in that manner might give this:
fun oldest_of (d, d') = if is_older (d, d') then d else d'
fun oldest [] = NONE
| oldest (d::ds) = case oldest ds of
NONE => SOME d
| SOME d' => SOME (oldest_of (d, d'))
That is,
If the list is empty, there is no oldest date
Otherwise, find the oldest date in the input's tail;
If there isn't one, the input's first element must be the oldest
Otherwise, pick the oldest of that and the input's first element
Now it's (hopefully) obvious that the NONE case in the recursion can only occur if the tail, ds, is empty - that is, if the input has exactly one element.
Let's lift that out into its own case:
fun oldest [] = NONE
| oldest [d] = SOME d
| oldest (d::ds) = SOME (oldest_of (d, valOf (oldest ds)))
This reads a lot like this definition of what the oldest date is:
If there are no dates, there is no oldest date
If there is only one date, that is the oldest
If there are at least two dates, it is the oldest of the first date and the oldest one of the rest
which doesn't need much inductive thinking.
You can prove it by induction:
In the case of an empty list, oldest will return NONE.
If the list contains an element, we'll go into the else branch, letting d be NONE, because tl of a list with one element returns an empty list. isSome d will be false, which is why we will return SOME(hd dates) — the only element, which is by definition the oldest.
Assuming the function works for the case of a list of n-1 items, let's see what happens when the list has n items: We will go into the else branch and assign to d the oldest element from the tail of the list (which works, because it contains n-1 items). Now there's two possible scenarios:
a. d is older than the first element of the list. In that case, d will be returned, because both isSome d and is_older(valOf d, hd dates) will be true.
b. d is not older than the first element of the list. We will therefore return SOME(hd dates) — the first element of the list.
We have shown that it works for n elements if it works for n-1, and we have shown that it works for n=0 and n=1 (technically we could have skipped step 2). It will therefore work for a list of any size.
I have a piece of code that does the following: group 3 elements of a list of n elements. The main function is called group_by_3. For example, executing group_by_3 [1;2;3;4;5;6;7] will give me ([1;2;3],[4;5;6],[7]).
let group_by_3 lst =
let accum = ( [], [], 0 )
in
let f (all_groups, current_group, size) x =
if size = 3
then ( (List.rev current_group) :: all_groups,
[x], 1 )
else ( all_groups, x::current_group, size+1)
in
let (groups, last, _) = List.fold_left f accum lst
in List.rev ( List.rev last :: groups)
I don't really understand why this works (it is provided in class).
What are all_groups, current_group, size?
What does this do?
if size = 3
then ( (List.rev current_group) :: all_groups,
[x], 1 )
else ( all_groups, x::current_group, size+1)
Thank you!
All groups is the final answer, current is the group of three elements filled while parsing the input and size is the number of elements actually in current I guess.
Do you know the behavior of fold_left?
What are all_groups, current_group, size?
These are the three pieces of state required to produce the groupings by visiting each item in the input sequence. These individual states are combined in a 3-tuple to form a single state for the fold. Ultimately we'll only care about all_groups, and the other two are just intermediate state necessary to construct that.
all_groups: This is a list value that accretes completed groupings. Whenever we've seen enough new elements to satisfy the group size, we make a new group and add it to this list.
current_group: This is also a list value, but more of a temporary buffer to build up a grouping until it reaches size. When it's big enough, it gets added to all_groups and is reset to a new group/list with the current item [x].
size this is just a counter to track how many items are in current_group.
What does this do?
if size = 3 simply decides whether we want to keep accumulating elements or if we've got enough for a grouping.
then ( (List.rev current_group) :: all_groups, [x], 1 ) is building/returning the new accumulator value, which is a 3-tuple of all_groups, current_group, and size. The List.rev call is necessary because of the way the list is being grown, in the else branch; it's fastest to add items to the front of a list, but this is the reverse of the input sequence thus we reverse them. x is the current item, which will be the first item in the new, growing group. 1 is of course the size of that new group.
else ( all_groups, x::current_group, size+1) is popping the current item x onto the front of the current_group list and incrementing the size counter.
Below that section is the logic that takes care of any straggler items that don't fit neatly into groupings of three.
I see this code in the example of Elixir:
defmodule Recursion do
def print_multiple_times(msg, n) when n <= 1 do
IO.puts msg
end
def print_multiple_times(msg, n) do
IO.puts msg
print_multiple_times(msg, n - 1)
end
end
Recursion.print_multiple_times("Hello!", 3)
I see here the same function defined twice with different arguments, and I want to understand this technique.
Can I look at them as at overloaded functions?
Is it a single function with different behavior or are these two different functions, like print_only_once and print_multiple_times?
Are these functions linked anyhow or not?
Usually in functional languages a function is defined by clauses. For example, one way to implement Fibonacci in an imperative language would be the following code (not the best implementation):
def fibonacci(n):
if n < 0:
return None
if n == 0 or n == 1:
return 1
else:
return fibonacci(n - 1) + fibonacci(n - 2)
To define the function in Elixir you would do the following:
defmodule Test do
def fibonacci(0), do: 1
def fibonacci(1), do: 1
def fibonacci(n) when n > 1 do
fibonacci(n-1) + fibonacci(n - 2)
end
def fibonacci(_), do: nil
end
Test.fibonacci/1 is only one function. A function with four clauses and arity of 1.
The first clause matches only when the number is 0.
The second clause matches only when the number is 1.
The third clause matches with any number greater than 1.
The last clause matches anything (_ is used when the value of the variable is not going to be used inside the clause or is not relevant for the match).
The clauses are evaluated in the order they are declared, so for Test.fibonacci(2) will fail in the first 2 clauses and match the third one because 2 > 1.
Think of clauses as a more powerful if statement. The code looks cleaner this way. And is very useful for recursion. For example, a map implementation (the language already provide one in Enum.map/2):
defmodule Test do
def map([], _), do: []
def map([x | xs], f) when is_function(f) do
[f.(x) | map(xs, f)]
end
end
First clause matches an empty list. No need to apply a function.
Second clause matches a list where the first element (head) is x and the rest of the list (tail) is xs and f is a function. It applies the function to the first element and recursively calls map with the rest of the list.
Calling Test.map([1,2,3], fn x -> x * 2 end) will give you the following output [2, 4, 6]
So, a function in Elixir is defined with one or more clauses where every clause have the same arity as the rest.
I hope this answers your question.
In the example you posted both definitions of the function have the same number of arguments: 2, this "when" thing is a guard, but you can also have definitions with many arguments. First, guards -- they are uses to express what cannot be written as a mere matching, like the second line of the following:
def fac(0), do: 1
def fac(n), when n<0 do: "no factorial for negative numbers!"
def fac(n), do: n*fac(n-1)
-- since it's not possible to express being negative number by just equality/matching.
Btw this fac is a single definition, only with three cases. Notice the coolness of using constant "0" in the position of argument :)
You can think of this as it would be nicer way to write:
def fac(n) do
if n==0, do: 1, else: if n<0, do: "no factorial!", else: n*fac(n-1)
end
or a switch case (which even looks pretty close to the above):
def fa(n) do
case n do
0 -> 1
n when n>0 -> n*fa(n-1)
_ -> "no no no"
end
end
only "looks more fancy". Actually it turns out certain definitions (e.g. parsers, small interpreters) look much better in the former than latter style. Nb guard expressions are very limited (I think you can't use your own function in guard).
Now the real thing, varying number of arguments -- check this out!
def mutant(a), do: a*a
def mutant(a,b), do: a*b
def mutant(a,b,c), do: mutant(a,b)+mutant(c)
e.g.
iex(1)> Lol.mutant(2)
4
iex(2)> Lol.mutant(2,3)
6
iex(3)> Lol.mutant(2,3,4)
22
It works a bit similar like (lambda arg ...) in scheme -- think of mutant as taking all its arguments as a list and matching over it. But this time, elixir treats mutant as 3 functions, mutant/1, mutant/2, and mutant/3 and will refer to them as such.
So, to answer your question: these are not like overloaded functions, but rather scattered/fragmented definitions. You see similar ones in functional languages like miranda, haskell or sml.
Is it possible to call make-array function with a list as parameter? For example:
(make-array '((length '("a" "b")) (length '("r" "8" "5"))))
return:
#<TYPE-ERROR expected-type: NUMBER datum: (LENGTH '(...
Even if I try to cast the result of length with the following command:
(coerce (length '(1)) 'number)
it works for one dimension array but not for two dimensions.
Is it possible to call make-array function with a list as parameter?
Yes, in fact you always have to pass it a list designator, but it has to be a list (or list designator) of integers. The list '((length '("a" "b")) (length '("r" "8" "5")))) has two lists as its elements, not integers. E.g., if you do (first '((length '("a" "b")) (length '("r" "8" "5"))))), you get (length '("a" "b")), not 2. You'd need to do (make-array (list (length …) (length …)) …) instead.
It's described pretty clearly in the documentation for make-array in the HyperSpec:
Function MAKE-ARRAY
Syntax:
make-array dimensions &key element-type initial-element initial-contents adjustable fill-pointer displaced-to
displaced-index-offset
=> new-array
Arguments and Values:
dimensions—a designator for a list of valid array dimensions.
E.g., (make-array '(2 2)) returns a 2 × 2 array. Or, if you need to dynamically compute the dimensions, just list them together. E.g., (make-array (list (length '(a b c)) (length '(d e)))) returns a 3 × 2 array.
Note that the argument is designator for a list. The glossary entry says:
list designator n. a designator for a list of objects; that is, an
object that denotes a list and that is one of: a non-nil atom
(denoting a singleton list whose element is that non-nil atom) or a
proper list (denoting itself).
That means that when you do (make-array 5), the 5 is actually acting as a designator for the list (5). You can really think of make-array always accepting a list as the first argument, but that in the case of a one-element list, you can just pass the single element instead, since it's unambiguous what you'd want.
Related
These are related, but not quite duplicates, since they are about how to create a list to pass to make-array, whereas this question is about whether a list can be passed to make-array.
How to make an array with size received as arguments in a function in LISP?
How to modify this "make-matrix" function?
Simple rule 1: if you quote it, it does not get evaluated.
This is data, not code: '((length '("a" "b")) (length '("r" "8" "5"))).
Why? Because it is quoted.
Simple rule 2: if you want to compute something, then write Lisp code, not literal data.
(list 1 2) -> (1 2)
(list (length '(a b c)) (length '(1 2 3 4))) -> (3 4)
Addressing an unanswered aspect of the subject of the question: much like Common Lisp lists, multidimensional arrays also have a literal representation, which can be convenient in some situations.
Lists
(list 'a 'b 'c)
;; is equivalent to
'(a b c)
A vector (single dimensional array) is represented as #[n](foo*) -- n,optional, being the number of elements and foo being the items in the vector, e.g.
(vector 1 2 3 4)
;; is equivalent to
#4(1 2 3 4)
;; or
#(1 2 3 4)
A 'proper' multidimensional array, i.e. an array larger than one dimension, is represented as: #nA<sequence> where n is the number of dimensions and <sequence> has a structure similar to a nested list, e.g.
(make-array '(2 3) :initial-contents '((a b c) (d e f)))
;; is equivalent to the following. Note, the 'inner most' array arrays must have the same number of objects, i.e. lisp won't auto-fill them with nil or anything else.
#2A((A B C) (D E F))
But you don't need to memorize that. Like many other forms, the Lisp reader accepts as input whatever it printed as output of make-array. (Given some caveats that I won't go into, or rather will leave as an exercise for the reader!)