I am trying to write a function in sml that takes in a list of pairs and returns pair of two list of all the elements
Meaning if the input is [(1, 2.0), (2, 3.0)]
The output should be ([1, 2], (2.0, 3.0))
fun divide nil = (nil , nil)
| divide [(a, b)::nil] = ([a], [b])
| divide [(a, b)::myTl] =
let
val (x, y) = divide myTl
in
(a::x, b::y)
end
;
Never the less the sml interpreter returns the following err
Error: operator and operand do not agree [tycon mismatch]
operator domain: ('Z * 'Y) list list
operand: ('Z * 'Y) list
in expression:
divide myTl
The error message you're seeing is because you've (inadvertently) declared a function with domain ('a * 'b) list list due to your input patterns, so your recursive call is not well typed.
The most straightforward fix is to correct for the incorrect use of [ ] around the argument to the function---this is making a singleton list, instead of just grouping the pattern. Thus you'd want to use ( ) instead.
fun divide nil = (nil , nil)
| divide ((a, b)::nil) = ([a], [b])
| divide ((a, b)::myTl) =
let
val (x, y) = divide myTl
in
(a::x, b::y)
end
Your second base case is also extraneous, so we could further revise this to
fun divide [] = ([], [])
| divide ((a, b)::xs) =
let
val (x, y) = divide xs
in
(a::x, b::y)
end
Related
I have experience with functional programming in general, but I'm new to F#, and I can't get this code to compile no matter what I try:
let group2<'T> (sq: seq<'T>) : seq<'T * 'T> =
Seq.fold (fun (p, l) b -> match p with
| None -> (Some b, l)
| Some v -> (None, (v, b) :: l)) (None, []) sq
I don't understand what this error message is trying to tell me, and I can't for the life of me figure out why it won't compile as-is;
main.fs(2,19): error FS0001: This expression was expected to have type
'seq<'T * 'T>'
but here has type
''a * 'b'
main.fs(4,65): error FS0001: This expression was expected to have type
'seq<'T * 'T>'
but here has type
''a * 'b'
anyone with more F# experience have some advice?
So if you update your code like this
let group2<'T> (sq: seq<'T>) : seq<'T * 'T> =
Seq.fold (fun (p ,l) b -> match p with
| None -> (Some b, l)
| Some v -> (None, (v, b) :: l)) (None, []) sq
|> snd
|> List.rev
|> Seq.ofList
It can work (by removing the state, and converting back from list to sequence). For example
group2 [1;2;3;4]
yields
[(1, 2); (3, 4)]
It's not very idiomatic as it mixes sequences and lists.
A more idiomatic code only for (even) lists:
let rec group2 (xs:'T list) =
match xs with
| [] -> []
| x::y::xs -> ( x, y)::group2 xs
| _ -> failwith "not even"
Basically you deal with 3 choices,
The list is empty, there are no pairs you return an empty list.
There are two items at the start, you pair them in a tuple and process the rest of the list recursively
There's only one item left, we fail because it's not posible to create a tuple with nothing*
If you want to consider odd lists, you can use option types: e.g. None/Some
let rec group2 (xs:'T list) =
match xs with
| [] -> []
| [x] -> [Some x, None]
| x::y::xs -> (Some x,Some y)::group2 xs
Finally you could use the chunkBySize library function for either (even) lists or sequences:
[1;2;3;4]
|> Seq.chunkBySize 2
|> Seq.map (fun a -> a.[0], a.[1])
or
[1;2;3;4]
|> List.chunkBySize 2
|> List.map (fun a -> a.[0], a.[1])
Hello I'm trying to write a program in OCaml and was wondering if there is a way to get from list of pairs : [(1,2);(2,3);(3;5)] to a list where pairs are multiplied [2;6;15] this is what i have tried but it's giving me Exception: Failure "hd"
let rec mul l=
let x=(List.hd l) and y=(List.tl l) in
((fst x)*(snd x))::(mul y);;
mul [(3, 5); (3, 4); (3, 3);];;
What you want essentially is List.map (uncurry ( * )).
# let uncurry f (a, b) = f a b;;
val uncurry : ('a -> 'b -> 'c) -> 'a * 'b -> 'c = <fun>
# List.map (uncurry ( * )) [(3, 5); (3, 4); (3, 3);];;
- : int list = [15; 12; 9]
(uncurry is a basic FP function, but unfortunately it isn't defined in OCaml's fairly sparse standard library. But as you can see the definition is straightforward.)
To be honest, I think there must be simpler methods. Specifically, you have a list of n elements which are pairs (so a list of type (int * int) list) and you want to get a list of the same size, but which is the result of multiplying the two members of the pair. So, going from an (int * int) list to an int list.
As the objective is to preserve the size of the list, you can rephrase the statement by saying "I would like to apply a function on each element of my list". It is possible to do this manually, using, for example, pattern matching (which makes it possible to be explicit about the treatment of the empty list):
let rec mult my_list =
match my_list with
| [] -> (* case if my list is empty *)
[] (* The process is done! *)
| (a, b) :: tail -> (* if I have, at least, one element)
(a * b) :: (mult tail)
But generally, applying a function to each element of a list and preserving its size is called "mapping" (roughly), and fortunately there is a function in the standard OCaml library which allows this, and it is called, logically: List.map, here is its type: val map : ('a -> 'b) -> 'a list -> 'b list which could be translated as: give me a function which goes from 'a to 'b, a list of 'a and I can produce a list of 'b for you.
Here, we would like to be able to apply a function that goes from (int * int) -> int, for example: let prod (x, y) = x * y. So let's try to reimplement mult in terms of map:
let mult my_list =
let prod (x, y) = x * y in
List.map prod my_list
And voila, the pattern captured in the first purpose is exactly the idea behind List.map, for each element of a list, I apply a function and I keep the result of the function application.
Here is a working solution with the least amount of modification to your original code:
let rec mul l =
match l with
| [] -> [] (* <-- Deal with the base case *)
| _ -> (* Same as before --> *)
let x = (List.hd l) and y = (List.tl l) in
((fst x)*(snd x))::(mul y);;
Note that we just need to consider that happens when the list is empty, and we do that by matching on the list. The recursive case stays the same.
Does this function take two int lists "x and y" and return an int list of y-x?
let rec fun4 (l: int list) :int list =
begin match l with | [] -> []
| [_] -> []
| x::y::rest -> (y-x)::(fun4 (y::rest))
end
A list is defined as a recursive type:
type 'a list =
| [] of 'a list (* the empty case *)
| ( :: ) of 'a * 'a list
So you basically have two constructors: [] which is the empty list, and x :: other_list which is a list with x as head and other_list as tail. The use of these constructors makes it easy to define a list: [0; 1; 2; 3] is exactly the same of 0 :: 1 :: 2 :: 3 and of (::) (0, (::) (1, (::) (2, (::) (3, [])))) (which is not very pleasant to read).
Recursive algebraic types, here we have the conjunction of sums ([] and (::)) and products (('a * 'a list)), combined with pattern matching make it possible to describe all sorts of common data structures, as well as their functions for consuming, modifying etc.
In your example, you use pattern matching to deconstruct the list:
let rec fun4 my_list =
match my_list with
(* if my list is empty, I can't process the function so
I return the empty list *)
| [] -> []
(* if my list my list has only one element, I can't process the function
so, like in the previouse case, I return the empty list *)
| [ _ ] -> []
(* Here is the last case of the function, If I almost have two elements in the
list. Remember that empty list is also a list ! *)
| x :: y :: rest -> (y - x) :: (fun4 (y :: rest))
As you can see, Recursives Algebraic data types coupled with pattern matching are a powerful for describing data structures (like list but also many others) and for writing function that use those data structures.
I am trying to write a simple add function that takes two real lists and adds the matching indices together and generates a real list, but for some reason I can't get it to accept real lists as the parameters, but instead only int lists.
fun add (nil, _) = nil
| add (_, nil) = nil
| add (a :: b, x :: y) = (a + x) :: add (b,y)
When I try running my test input, val addTest = add([1.0, 2.0, 3.0], [0.1, 0.2, 0.3]); it gives me:
Error: operator and operand do not agree [tycon mismatch]
operator domain: int list * int list
operand: real list * real list
And I am just curious as to why SML is defaulting to an int list even though the "+" operand is used for both reals and ints. Shouldn't it be accepting `a list instead of just int lists?
Yes, + (along with other arithmetic operators) is overloaded but not parametrically polymorphic.
So you can do 1.0 + 1.0 and 1 + 1 and they give a real and an int respectively.
But fun f x y = x + y can infer to either, so the compiler defaults to the int overload.
As an addition to your own answer, you can do with a single : real in your code:
fun add ([], _) = []
| add (_, []) = []
| add (x::xs, y::ys) = (x + y : real) :: add (xs, ys)
and it will infer that you must mean real in all the other places, too.
You could generalise this operation into one called zipWith:
- fun zipWith f [] _ = []
| zipWith f _ [] = []
| zipWith f (x::xs) (y::ys) = f (x, y) :: zipWith f xs ys
> val ('a, 'b, 'c) zipWith = fn :
('a * 'b -> 'c) -> 'a list -> 'b list -> 'c list
- val add = zipWith (op + : real * real -> real)
> val add = fn : real list -> real list -> real list
- add [1.0, 2.0, 3.0] [4.0, 5.0, 6.0];
> val it = [5.0, 7.0, 9.0] : real list
I found out that the default behavior for SML in a case like this is to default to int behavior, so if you have an operand that works for either reals or ints it will be evaluated as an int. As for the method above I was able to get my desired behavior by specifying the parameters in the tuple to be real lists like so:
fun add (nil, _) = nil
| add (_, nil) = nil
| add (a::b : real list, x::y : real list) = (a + x) :: add (b,y)
I want to make a function that looks up a String in a list of type [(String, Int)] and returns the Int paired with the String.
Like this:
λ> assignmentVariable "x" [("x", 3), ("y", 4), ("z", 1)]
3
Here's what I've tried:
assignmentVariable :: String -> [(String, Int)] -> Int
assignmentVariable [] = error "list is empty"
assignmentVariable n (x:xs) = if x == n
then xs
else assignmentVariable
How could I write this?
Let's take the posted code:
assignmentVariable::String -> [(String, Integer)] -> Integer
assignmentVariable [] = error "list is empty"
assignmentVariable n (x:xs) = if x == n then xs else ...
The first equation has only one argument, while the second has two. Let's fix that.
assignmentVariable::String -> [(String, Integer)] -> Integer
assignmentVariable _ [] = error "list is empty"
assignmentVariable n (x:xs) = if x == n then xs else ...
Since we do x == n, these variables must be of the same type.
However, n::String and x::(String,Integer). We need to split x into its components before comparing.
assignmentVariable::String -> [(String, Integer)] -> Integer
assignmentVariable _ [] = error "list is empty"
assignmentVariable n ((m,x):xs) = if m == n then xs else ...
The result xs is a list, not an Integer as the type signature suggests. You just want x there.
assignmentVariable::String -> [(String, Integer)] -> Integer
assignmentVariable _ [] = error "list is empty"
assignmentVariable n ((m,x):xs) = if m == n then x else ...
Finally, the recursive call. When m/=n, we want to try the other pairs in the list xs, so:
assignmentVariable::String -> [(String, Integer)] -> Integer
assignmentVariable _ [] = error "list is empty"
assignmentVariable n ((m,x):xs) = if m == n
then x
else assignmentVariable n xs
You want to pattern-match on the pair.
assignmentVariable expected ((key, value) : rest)
If the variable name matches the expected name, the first element of the pair…
= if key == expected
You return the associated value, the second element of the pair.
then value
Otherwise, you try to find the value in the rest of the list.
else assignmentVariable expected rest
You can implement it without pattern-matching, of course:
assignmentVariable expected list
= if expected == fst (head list)
then snd (head list)
else assignmentVariable expected (tail list)
However, this is not the usual style in Haskell code.
This function also exists in the Prelude, by the name of lookup.
You're halfway there, actually!
First, it would be better to make a more general type signature, and a better name:
myLookup :: (Eq a) => a -> [(a, b)] -> b
You've done well to have sorted out the edge case of [], but you've not quite finished:
myLookup _ [] = error "myLookup: empty list."
myLookup n ((x, b):xs) = if x == n
then b
else myLookup n xs
Your problem was what you put after the else: you weren't recursively calling the function, you were returning the function, which doesn't make any sense - you need to call it again with different arguments to recur.
If you want to improve, try making a similar function of type Eq a => a -> [(a, b)] -> Maybe b for a challenge.
Just for posterity, I would like to propose an alternative implementation:
assignmentVariables :: Eq a => a -> [(a, b)] -> [b]
assignmentVariables n xs = [v | (n', v) <- xs, n == n']
You can run it in ghci:
> assignmentVariables "x" [("x", 3), ("y", 4), ("z", 1)]
[3]
"Ah!", I hear you say, "But it returns [3] and not 3!". But don't give up on it yet; there are several advantages of the behavior of this function over the behavior you proposed.
The type of assignmentVariables is more honest than the type of assignmentVariable. It doesn't promise to return a value when it doesn't find the given key in its lookup table. This means that, unlike your version, this version will not cause runtime crashes. Moreover, it has a clean way to report the unlikely situation where there are conflicts in the lookup table: it will return all values associated with the given key, even if there are many.
The consumer of the call then gets to decide how to handle the exceptional cases: one can write
case assignmentVariables key lookupTable of
[] -> -- do something appropriate to complain about missing keys
[value] -> -- do something with the value
values -> -- do conflict resolution; for example, use the first value or complain or something
or may simply treat the output of assignmentVariables as a nondeterministic value. The key here is that you are not locked into one behavior (which, of all the choices, crashing? really?).