I have the following function table which takes a list of tuples (x's are strings and y's are a list of strings) and I want to return a tuple of x1 and the length of the list y1. I tried it with this simple function:
let rec table lst = function
| [] -> []
| [(x1, y1, x2, y2)] -> [(x1, (List.length y1))]
| (x1_h, y1_h, x2_h, y2_h) :: tail -> (x1_h, (List.length y1_h))::(table tail)
But the following error occured:
Error: This expression has type
('a * 'b list * 'c * 'd) list -> ('a * int) list
but an expression was expected of type ('a * int) list
I'm not really sure what I did wrong there.
function takes an argument implicitly and pattern matches on that. In other words:
let f = function | ...
is equivalent to
let f lst = match lst with | ...
So when you write
let rec table lst = function | ...
That translates to
let rec table lst lst2 = match lst2 with | ...
The error points to the recursive call, table tail, because it is partially applied and returns a function ('a * 'b list * 'c * 'd) list -> ('a * int). table tail tail would return ('a * int list) as expected and is completely valid. But since lst is unused in your function, you can just remove it instead.
Related
As the title suggests, I want to write a function that takes in an 'a list and an expression that evaluates to either true or false when elements of the list are passed into it. The function should return an 'a list of all the elements that don't satisfy the predicate given. The type should be
'a list -> ('a -> bool) -> 'a list
when it is working properly.
This is what I have so far,
let rec filter (x: 'a list) pred =
if x = [] then [] else
if x -> pred = true then remove_if (x.tl) pred else
x :: xs remove_if (x.tl) pred ;;
I tried some other ways of writing it but in my closest attempt the type ended up evaluating improperly.
Here's something to get you started..
let rec filter f lst =
match lst with
| [] -> []
| hd::tl ->
if (f hd)
(*The rest of the function goes here*)
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.
This question already has an answer here:
Swap pairs of elements in a list using pattern matching
(1 answer)
Closed 5 years ago.
I am trying to write a function to swap a pair of tuples inside of a list like this:
- pairSwap [(1, 2), (3, 4), (5, 6);
[(2,1),(4,3),(6,5)]
I am having a hard time figuring out what I am doing wrong with my syntax while declaring the function. This is what I have so far:
fun pairSwap ((a : 'a, b: 'a) list) : (('a, 'a) list) =
...
;
Where am I going wrong?
Edit:
Solution
fun pairSwap (t : ('a * 'a) list) : ('a * 'a) list =
if null t
then []
else
let
val v = hd t
in
(#2 v, #1 v)::pairSwap (tl t)
end
;
Since you have provided a solution in the meantime, here is some feedback on it:
You don't really need the type annotations. You can let type inference do the work.
fun pairSwap t = ...
You can use null, hd and tl, but consider pattern matching:
fun pairSwap [] = []
| pairSwap ((x,y)::ps) = (y,x)::pairSwap ps
This also makes the let-expression redundant.
As Matt points out, the type for this function is ('a × 'b) list → ('b × 'a) list, which means you can also swap pairs where the left side has a different type ('a) than the right side ('b), e.g.:
- pairSwap [("hello",42),("world",43)];
val it = [(42,"hello"),(43,"world")] : (int * string) list
You need to pull the variable out of the pair type annotation:
fun pairSwap (arg : ('a * 'b) list) : ('b * 'a) list = ...;
Note that I've also changed it from what you had to what the title requested: ('a * 'a) list -> ('a * 'a) list to ('a * 'b) list -> ('b * 'a) list
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 asked this question a few days ago but now I have more understanding on the subject. But I still get problem that operator and operand dont agree:
Using ListPair.foldr I need to create a function zipWith that combines pairwise two lists. The type of the overall function should be:
zipWith : ('a * 'b -> 'c) -> 'a list -> 'b list -> 'c list
ListPair.foldr : ('a * 'b * 'c -> 'c) -> 'c -> 'a list * 'b list -> 'c
- zipWith (fn (x, y) => x + y) [1,2,3,4] [10,20,30,40];
val it = [11,22,33,44] : int list
My attempt:
fun zipWith xs ys = ListPair.foldr(zipWith(x,y,z) => (x+y)::z) 0 xs ys
There are several things wrong in your attempt:
The parameters. You have zipWith xs ys, but the type says that the first parameter has to be a function, so change that to zipWith f xs ys.
You're calling zipWith recursively. ListPair.foldr takes care of that for you, though, so don't.
You're giving ListPair.foldr 0 as its starting value. Fold-functions always take a starting value of the same type as the return value - we want zipWith to return a list, so the fold-function should take a list as its starting value. The empty list, that is.
Think about how ListPair.foldr works. We can do it one parameter at a time. The type of ListPair.foldr is:
fn : ('a * 'b * 'c -> 'c) -> 'c -> 'a list * 'b list -> 'c
The first parameter is a function with the type:
fn : 'a * 'b * 'c -> 'c
Let's make a toy function as an example:
fun foo (a, b, acc) = a+b :: acc
This function takes two numbers and a list, adds the two numbers together, puts them in front of the list, and returns it. The type is:
fn : int * int * int list -> int list
Which corresponds nicely with our type signature from the first parameter of ListPair.foldr.
Now, let's look at the type of ListPair.foldr foo.
fn : int list -> int list * int list -> int list
The next parameter is an int list - the starting value for the folding. Great, we already figured out that this is the empty list. The type of ListPair.foldr foo [] is:
fn : int list * int list -> int list
The last parameter is a tuple containing two lists. We put in some random lists, and try it out in an sml interpreter:
- ListPair.foldr foo [] ([1,2,3],[10,20,30])
> val it = [11, 22, 33] : int list
Now, all you need to do is to replace the parameters to ListPair.foldr (foo and the two random lists) with parameters from zipWith, and you're done.