I need to implement a function
ziprev : 'a list -> 'b list -> ('a * 'b) list
- ziprev [1,2,3,4] [10,20,30,40];
val it = [(1,40),(2,30),(3,20),(4,10)] : (int * int) list
Using a function that I already created:
- zipW (fn (x, y) => x + y) [1,2,3,4] [10,20,30,40];
val it = [11,22,33,44] : int list
and the List.rev from the library.
I have no idea how to do a function with two libraries. Any suggestions?
Hint 1:
Compare the result of your ziprev with
List.zip [1,2,3,4] [10,20,30,40]
You should see a fairly obvious pattern.
Hint 2:
List.rev reverses a list.
Hint 3:
Can you use zipW to implement List.zip?
That is, if you want to say
normalzip xs ys = zipW something xs ys
what would something be?
Related
In OCaml, a typical fold function looks like this:
let rec fold (combine: 'a -> 'b -> 'b) (base: 'b) (l: 'a list) : 'b =
begin match l with
| [] -> base
| x :: xs -> combine x (fold combine base xs)
end
For those familiar with OCaml (unlike me), it should be pretty straightforward what it's doing.
I'm writing a function that returns true when all items in the list satisfy the condition: if condition x is true for all x in some list l. However I'm implementing the function using a fold function and I'm stuck. Specifically I don't know what the list should return. I know that ideally the condition should be applied to every item in the list but I have no idea how the syntax should look. x && acc works but it fails a very simply test (shown below)
let test () : bool =
not (for_all (fun x -> x > 0) [1; 2; -5; -33; 2])
;; run_test "for_all: multiple elements; returns false" test
Here is my preliminary attempt. Any help is appreciated:
let for_all (pred: 'a -> bool) (l: 'a list) : bool =
fold (fun(x:'a)(acc: bool)-> _?_&&_?_ )false l
let rec fold (combine: 'a -> 'b -> 'b) (base: 'b) (l: 'a list) : 'b =
match l with
| [] -> base
| x::xs -> combine x (fold combine base xs)
let for_all (pred: 'a -> bool) (lst: 'a list) =
let combine x accum =
(pred x) && accum
in
fold combine true lst
Your combine function should not do x && base because elements of the list are not usually bool. You want your predicate function first evaluate the element to bool, then you "and" it with the accumulator.
There is no need for begin and end in fold. You can just pattern match with match <identifier> with.
There are two widespread types of fold: fold_left and fold_right. You're are using fold_right, which, basically, goes through the whole list and begins "combining" from the end of the list to the front. This is not tail-recursive.
fold_left, on the other hand goes from the front of the list and combines every element with the accumulator right away. This does not "eat up" your stack by a number of recursive function calls.
I am a new to SML and I want to write a function splitup : int list -> int list * int list that given a list of integers creates from two lists of integers, one containing the non-negative entries, the other containing the negative entries.
Here is my code :
fun splitup (xs :int list) =
if null xs
then ([],[])
else if hd xs < 0
then hd xs :: #1 splitup( tl xs)
else hd xs :: #2 splitup( tl xs)
Here's the warning i get:
ERROR : operator and operand don't agree
ERROR : types of if branches do not agree
The function splitup(tl xs) should return int list * int list so i think my recursion should be all right.
What is the problem and how can i fix it ?
The problem is that
hd xs :: #1 splitup( tl xs)
and
hd xs :: #2 splitup( tl xs)
are lists – you can tell from the :: – not pairs of lists as the result should be.
For the non-empty case, you need to first split the rest of the list, then attach the head to the correct part of the result and add it the other part of the result in a pair.
It's also a good idea to get used to pattern matching, as it simplifies code lot.
Something like this:
fun splitup [] = ([], [])
| splitup (x::xs) = let (negatives, non_negatives) = splitup xs
in if x < 0
then (x :: negatives, non_negatives)
else (negatives, x :: non_negatives)
end
There is already List.partition: ('a -> bool) -> 'a list -> 'a list * 'a list, a higher-order library function that does this. In case you want to split up integers into (negative, non-negative):
val splitup = List.partition (fn x => x < 0)
Learning OCaml from here.
I want to verify if I have understood how this snippet of OCaml code works
List.fold_left (fun acc x -> acc + x) 0 [ 1; 2; 3; 4 ]
I have an intuition that this is an equivalent to the reduce function in Python. Specifically, I think it is equivalent to
reduce(lambda x, y: x + y, [1, 2, 3])
The anonymous function is taking two parameters - acc and x and returns a single value acc + x. I understand that initially, the first argument acc will be 0 but how does it know that the second argument has to be the first element of the list?
What I think is happening is that fold_left provides the two arguments to the anonymous function and then recursively calls itself with new arguments until the list becomes empty.
To confirm this I saw this.
When I define a function like let inc x = x + 1 I get something like val inc : int -> int = <fun> but in this case the signature is : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a = <fun>
What is 'a and how should I interpret this function signature so that List.fold_right f [a1; ...; an] b becomes f a1 (f a2 (... (f an b) ...))?
You are asking many questions.
I'm pretty sure that Python reduce is a fold, so your intuition is probably right.
You ask "how does it know that the second argument has to be the first element of the list?" Unfortunately, I don't think this is a well formed question. There's no "it" that knows anything. Most likely the answer is given by the definition of fold_left. It knows what to do because somebody wrote the code that way :-)
Here is the definition of fold_left from the standard library:
let rec fold_left f accu l =
match l with
[] -> accu
| a::l -> fold_left f (f accu a) l
In some sense, this should answer all your questions.
The type 'a in the type of fold_left is the type of the accumulator. The point is that you can use any type you want for the accumulator. This is why the fold is so powerful. As long as it matches the values accepted and returned by the folded function, it can be anything you want.
If I remember correctly, reduce is a simpler version of fold, which takes the first element of the list as starting element. I'd define it this way:
let reduce f = function
| x::xs -> fold_left f x xs
| [] -> failwith "can't call reduce on empty lists!"
If you enter it in OCaml, it will display its type:
val reduce : ('a -> 'a -> 'a) -> 'a list -> 'a
You can contrast it with fold_left's type:
('b -> 'a -> 'b) -> 'b -> 'a list -> 'b
The type variables 'a and 'b here mean that they can stand for any type. In your example, both 'a and 'b become int. If we insert the types, fold_left has the signature:
(int -> int -> int) -> int -> int list -> int
That's what we expected: + is a function which takes two ints and returns a new one, 0 is an int and the [1;2;3;4;] is a list of ints. The case that fold_left has two type variables and reduce only has one already gives a hint that it is more general. To see why we can look at the definition of reduce. Since the starting element of the fold is an element of the list, the types 'a' and 'b must be the same. That's fine for summing up elements, but say, we'd like to construct an abstract syntax tree for our summation. We define a type for this:
type exp = Plus of exp * exp | Number of int
Then we can call:
fold_left (fun x y -> Plus (x, (Number y))) (Number 0) [1; 2; 3; 4]
Which results in the expression:
Plus (Plus (Plus (Plus (Number 0, Number 1), Number 2), Number 3), Number 4)
A benefit of this tree is that you can nicely see what is applied first (0 and 1) - in case of addition this is not a problem, since it is associative (this means a+(b+c) = (a+b)+c) which is not the case for subtraction (compare e.g. 5-(3-2) and (5-3)-2).
If you want to do something similar with reduce, you will notice that OCaml complains about type errors:
reduce (fun x y -> Plus (x, (Number y))) [1; 2; 3; 4] ;;
Error: This expression has type exp but an expression was expected of type
int
In this case, we can wrap each integer as an expression in our input list, then the types agree. Since we already have Numbers, we don't need to add the Number constructor to y:
let wrapped = map (fun x -> Number x) [1; 2; 3; 4] in
reduce (fun x y -> Plus (x, y)) wrapped
Again, we have the same result, but we needed an additional function call to map. In the case of fold_left, this is not necessary.
P.S.: You might have noticed that OCaml gives the type of fold_left as ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a. I guess you will quickly realize that the name of the type variables doesn't play a role. To make it easier to compare, I switched the names such that the function is always applied to a list of 'a.
A little late, but the comparison between OCaml's folds and Python's reduce may be easier if you incorporate reduce's initializer argument.
Summing a list of ints in OCaml using a fold:
let sum = List.fold_left (+) 0 [1; 2; 3]
And using reduce in Python.
from functools import reduce
sum = reduce(int.__add__, [1, 2, 3], 0)
Here you can see the order of arguments is a bit different, but they're all there.
Python feels it's less likely you'll need the initializer, so leaves it at the end as an optional argument as a convenience. OCaml features the list as the last argument also as a convenience, as partial application makes it easy to write something like a sum function.
let sum = List.fold_left (+) 0
Rather than:
let sum lst = List.fold_left (+) 0 lst
I prepare for GATE Exam. one of the oldest question is unfamiliar with us. some experts please clarify this for us.
Which of the following can be a type for following ML function ?
my f(g, nil)=nil | f(g,x::xs)=(fn a ⇒ g(a,x))::f(g, xs);
1) (int *book → real) * bool list → (int → real) list
2) (bool *int → int) * real list → (bool → int) list
3) (int *int → real) * real list → (real → bool) list
4) (bool *real → int) * int list → (int → int) list
The Answer Sheets say (1) Is corrects. comments or short description for better understanding?
One of the first things you should do is rewrite the function definition yourself. This will force you to actually parse and understand it.
fun f (g, nil) = nil
| f (g, x :: xs) = (fn a => g (a, x)) :: f (g, xs);
So, f is a function, even the question says that, it must have type ... -> ...:
val f : ... -> ...
What does it receive? Let's take a look at the first pattern of the function:
fun f (g, nil) = nil
It's something of the form (a, b), which is a 2-tuple. The function's argument must be a tuple then:
val f : (... * ...) -> ...
Just by looking at the definition, we can't figure out what type g must have, but it uses nil for the second element of the tuple and nil is the empty list. That means the second component of the tuple must be a list of something:
val f : (... * ... list) -> ...
What else can we deduce? The return value is nil as well, which means that the function returns a list of something, unclear what that something is yet.
val f : (... * ... list) -> ... list
Ok, let's jump to the second pattern of the function definition now:
| f (g, x :: xs) = (fn a => g (a, x)) :: f (g, xs);
We don't find anything more about the type of the argument, we just got confirmation that the second element of the tuple must indeed be a list, because it uses the :: constructor.
Let's take a look at the body:
(fn a => g (a, x)) :: f (g, xs)
It looks like it's building a list, so it must return a list, which is in accordance with the return type we've sketched so far, i.e., ... list. Let's
try to figure out the type of elements.
It seems to add a function object as the head of the list built by recursively calling the function f, which we're currently investigating. So the elements of the list we're returning must be functions:
val f : (... * ... list) -> (... -> ...) list
What does that function do, though? It calls g with a 2-tuple argument. Now we can fill in some information about the first element of the 2-tuple f receives. It must be a function that receives a 2-tuple as well:
val f : (((... * ...) -> ...) * ... list) -> (... -> ...) list
Can we say anything about the a parameter received by the function literal added to the return list? Not really, just that it's passed to g. Can we tell anything about the type of x? Not really, just that it's passed to g. Moreover, is there any constraint between a and x? Doesn't look like it. So far, we can only tell that g's type must be looking something like this:
('a * 'b) -> 'c'
Where 'a, 'b and 'c are polymorphic types, i.e., any concrete type can satisfy them. You can view them as wholes. We can now fill in more of the type for the f function:
val f : ((('a * 'b) -> 'c) * ... list) -> (... -> ...) list
We can do more actually, we've already assign a type to the x variable, but that comes from the second argument of the 2-tuple received by f, so let's fill in that too:
val f : ((('a * 'b) -> 'c) * 'b list) -> (... -> ...) list
And we can even fill in the element type of the returned list, because we've already assigned types for that, too.
val f : ((('a * 'b) -> 'c) * 'b list) -> ('a -> 'c) list
We can remove some extra parenthesis from the type we came up with without changing the meaning, because of the type operator precedence rules:
val f : ('a * 'b -> 'c) * 'b list -> ('a -> 'c) list
Now, our function's type is complete. However, this type can't be found in the list of possible answers, so we'll have to see if any of them can be used instead of what we've determined. Why? Because our function type uses type variables, which can be filled in by concrete types. Let's take them one by one:
Choice 1
val f : ('a * 'b -> 'c) * 'b list -> ('a -> 'c) list
val f : (int * bool -> real) * bool list -> (int -> real) list
It looks like 'a could be int, 'b could be a bool (it's book in what you've pasted, but I'm assuming it was a typo) and 'c could be a real. All the replacements match these correspondences, so we declare that, yes, the first choice can be a possible type for the given function, even though not the most general. Let's take the second choice:
Choice 2
val f : ('a * 'b -> 'c) * 'b list -> ('a -> 'c) list
val f : (bool * int -> int) * real list -> (bool -> int) list
The type-variable to concrete -type correspondence table could be this:
'a -> bool
'b -> int
'c -> int
'b -> real
We can stop here because we can see that 'b was assigned to different types, so this function signature can't be assigned to the implementation we've been given.
Choice 3 and 4
They are similar to choice 2, but I'll let them as an exercise to the reader :)
I have a university course about functional programming, where I use SML. As a preparation for the exam, I am working on some of the older exam sets without solutions.
One of the only questions I really have problems with is the following question using foldl:
Consider the program skeleton: fun
addGt k xs = List.foldl (...) ... xs;
Fill in the two missing pieces
(represented by the dots ...), so that
addGt k xs is the sum of those
elements in xs, which are greater than
k. For example, addGt 4 [1, 5, 2, 7,
4, 8] = 5 + 7 + 8 = 20
I am sure this is really easy, but I have a very hard time understanding the foldl and foldr functions.
What I have now is the following (which seems to be very wrong if you ask my compiler!):
fun addGt(k,xs) = List.foldl ( fn x => if x > k then op+ else 0) 0 xs;
I would really appreciate some help with this question, and maybe a very short comment which would cast some light on the foldl and foldr functions!
A solution that I just though of is the following:
fun addGt(k, xs) = List.foldl (fn (x, y) => if x >= 5 then x + y else y) 0 xs;
But let me explain. First of all check the type of the List.foldl function, it's:
('a * 'b -> 'b) -> 'b -> 'a list -> 'b
So List.foldl is a curried function that takes as first parameter another function of type ('a * 'b -> 'b). You used (fn x => if x > k then op+ else 0) which has type int -> int. You should instead provide List.foldl with a function that takes a tuple of type int * int and returns an int, so something like this: (fn (x, y) => do stuff). That's why your code didn't compile, you passed a wrong type of function in foldl.
Now you can think of foldl this way:
foldl f b [x_1, x_2, ..., x_(n - 1), x_n] = f(x_n, f(x_(n - 1), ..., f(x2, f(x1, b)) ...)) where f is a function of type ('a * 'b -> 'b), b is something of type 'b and the list [x_1, x_2, ..., x_(n - 1), x_n] is of type 'a list.
And similar for foldr you can think it in this way:
foldr f b [x_1, x_2, ..., x_(n - 1), x_n] = f(x_1, f(x_2, ..., f(x_(n - 1), f(x_ n, b))
If you call foldl f s ls on a list, ls = [x1, x2, ..., xn], then you get the result:
f(xn, ... f(x2, f(x1, s)))
That is, it starts by finding
a1 = f(x1, s)
Then
a2 = f(x2, a1)
and so on, until it's through the list.
When it's done, it returns an.
You can think of the a-values as being a sort of accumulator, that is, ai is the result as it would be if the list was only [x1, x2, ..., xi] (or rather, the first i elements of the list).
Your function will usually have the form:
fn (x, a) => ...
What you then need to do is think: Okay, if I have the next element in the list, x(i+1), and the value ai, which is the result for the list [x1, x2, ..., xi], what do I need to do to find the value a(i+1), which is the result for the list [x1, x2, ..., xi, x(i+1)].
s can be thought of as the value given to the empty list.
foldr works the same way, only you start from the back of the list instead of from the front.