I have the following lists of tuples:
List 1:
[("key-1", Type1, Type2, Type3), ("key-2", Type1, Type2, Type3)]
List 2:
[("key-1", Type4), ("key-2", Type4)]
and I want to merge these tuples by its first component so that the following result is produced:
Result List:
[("key-1", Type1, Type2, Type3, Type4), ("key-2", Type1, Type2, Type3, Type4)]
In what way can I create the result list?
In general case I would go with converting to maps approach:
import Data.Map (Map)
import qualified Data.Map as Map
merge :: Ord a => [(a,b,c,d)] -> [(a,e)] -> [(a,b,c,d,e)]
merge left right = let
mleft = Map.fromList $ map (\(k, a,b,c) -> (k, (a,b,c))) left
mright = Map.fromList right
mergeL (a, b, c, d) acc = case Map.lookup a mright of
Nothing -> acc -- can't merge
Just e -> (a, b, c, d, e) : acc
in foldr mergeL [] left
Note this will get rid of keys that are not present in both lists. In case you need to preserve those you can generate entry with some default values for Nothing case, add similarly looking mergeR and concatenate two foldr in result.
Related
I've defined functions:
fun concaten(x,y) =
if (x = [])
then y
else hd(x) :: concaten(tl(x),y);
as well as:
fun existsin(x,L) =
if (L=[])
then false
else if (x = hd(L))
then true
else existsin(x,tl(L));
and am now trying to define a function of type (((list * list) -> list) -> list) that looks vaguely like the following:
fun strongunion(x,y) =
val xy = concaten(x,y);
if xy=[]
then []
if (existsin(hd(xy),tl(xy)) andalso x!= [])
then strongunion(tl(x),y)
else if (existsin(hd(xy),tl(xy)) andalso x = [])
then strongunion(x,tl(y))
else if (x != [])
then hd(xy) :: strongunion(tl(x),y)
else hd(xy) :: strongunion(x,tl(y));
which takes the "strong" union of two lists, i.e. it combats faulty inputs (lists with element duplicates). This code is, of course, syntactically invalid, but the reason I included it was to show what such a function would look like in an imperative language.
The way I started going about doing this was to first concatenate the lists, then remove duplicated elements from that concatenation (well, technically I am adding non-duplicates to an empty list, but these two operations are consequentially equivalent). To do this, I figured I would design the function to take two lists (type list*list), transform them into their concatenation (type list), then do the duplicate removal (type list), which would be of type (((list*list) -> list) -> list).
My issue is that I have no idea how to do this in SML. I'm required to use SML for a class for which I'm a TA, otherwise I wouldn't bother with it, and instead use something like Haskell. If someone can show me how to construct such higher-order functions, I should be able to take care of the rest, but I just haven't come across such constructions in my reading of SML literature.
I'm a bit unsure if strong union means anything other than just union. If you assume that a function union : ''a list * ''a list -> ''a list takes two lists of elements without duplicates as inputs, then you can make it produce the unions without duplicates by conditionally inserting each element from the one list into the other:
(* insert a single element into a list *)
fun insert (x, []) = [x]
| insert (x, xs as (y::ys)) =
if x = y
then xs
else y::insert(x, ys)
(* using manual recursion *)
fun union ([], ys) = ys
| union (x::xs, ys) = union (xs, insert (x, ys))
(* using higher-order list-combinator *)
fun union (xs, ys) = foldl insert ys xs
Trying this:
- val demo = union ([1,2,3,4], [3,4,5,6]);
> val demo = [3, 4, 5, 6, 1, 2] : int list
Note, however, that union wouldn't be a higher-order function, since it doesn't take functions as input or return functions. You could use a slightly stretched definition and make it curried, i.e. union : ''a list -> ''a list -> ''a list, and say that it's higher-order when partially applying it to only one list, e.g. like union [1,2,3]. It wouldn't even be fully polymorphic since it accepts only lists of types that can be compared (e.g. you can't take the union of two sets of functions).
I would like to iterate over all combinations of elements from a list of lists which have the same length but not necessarily the same type. This is like the cartesian product of two lists (which is easy to do in OCaml), but for an arbitrary number of lists.
First I tried to write a general cartesian (outer) product function which takes a list of lists and returns a list of tuples, but that can't work because the input list of lists would not have elements of the same type.
Now I'm down to a function of the type
'a list * 'b list * 'c list -> ('a * 'b * 'c) list
which unfortunately fixes the number of inputs to three (for example). It's
let outer3 (l1, l2, l3) =
let open List in
l1 |> map (fun e1 ->
l2 |> map (fun e2 ->
l3 |> map (fun e3 ->
(e1,e2,e3))))
|> concat |> concat
This works but it's cumbersome since it has to be redone for each number of inputs. Is there a better way to do this?
Background: I want to feed the resulting flat list to Parmap.pariter.
To solve your task for arbitrary ntuple we need to use existential types. We can use GADT, but they are close by default. Of course we can use open variants, but I prefer a little more syntactically heavy but more portable solution with first class modules (and it works because GADT can be expressed via first class modules). But enough theory, first of all we need a function that will produce the n_cartesian_product for us, with type 'a list list -> 'a list list
let rec n_cartesian_product = function
| [] -> [[]]
| x :: xs ->
let rest = n_cartesian_product xs in
List.concat (List.map (fun i -> List.map (fun rs -> i :: rs) rest) x)
Now we need to fit different types into one type 'a, and here comes existential types, let's define a signature:
module type T = sig
type t
val x : t
end
Now let's try to write a lifter to this existential:
let int x = (module struct type t = int let x = x end : T)
it has type:
int -> (module T)
Let's extend the example with few more cases:
let string x = (module struct type t = string let x = x end : T)
let char x = (module struct type t = char let x = x end : T)
let xxs = [
List.map int [1;2;3;4];
List.map string ["1"; "2"; "3"; "4"];
List.map char ['1'; '2'; '3'; '4']
]
# n_cartesian_product xxs;;
- : (module T) list list =
[[<module>; <module>; <module>]; [<module>; <module>; <module>];
[<module>; <module>; <module>]; [<module>; <module>; <module>];
...
Instead of first class modules you can use other abstractions, like objects or functions, if your type requirements allow this (e.g., if you do not need to expose the type t). Of course, our existential is very terse, and maybe you will need to extend the signature.
I used #ivg 's answer but in a version with a GADT. I reproduce it here for reference. In a simple case where only the types float and int can appear in the input lists, first set
type wrapped = Int : int -> wrapped | Float : float -> wrapped
this is a GADT without type parameter. Then
let wrap_f f = Float f
let wrap_i i = Int f
wrap types into the sum type. On wrapped value lists we can call n_cartesian_product from #ivg 's answer. The result is a list combinations: wrapped list list which is flat (for the present purposes).
Now to use Parmap, i have e.g. a worker function work : float * int * float * float -> float. To get the arguments out of the wrappers, I pattern match:
combinations |> List.map (function
| [Float f1; Int i; Float f2; Float f3] -> (f1, i, f2, f3)
| _ -> raise Invalid_argument "wrong parameter number or types")
to construct the flat list of tuples. This can be finally fed to Parmap.pariter with the worker function work.
This setup is almost the same as using a regular sum type type wrapsum = F of float | I of int instead of wrapped. The pattern matching would be the same; the only difference seems to be that getting a wrong input, e.g. (F 1, I 1, F 2.0, F, 3.0) would be detected only at runtime, not compile time as here.
I have a list of tuples, for example:
[(1,2), (3,4), (5,6)]
Now I have to write function which sum up the first an second element of each tuple and create a list of these values.
For the example above it should be:
[3, 7, 11]
This should be done with use of list comprehension. It's not allowed to use functions like map, filter and contact.
Any ideas how I could access the elements of the tuple in the list?
Try this:
[ x + y | (x,y) <- yourlist]
The trick is representing the two elements in a tuple from your input list as x and y and then dealing with them as needed.
Let's do it without list comprehensions, using functions from the Prelude:
map (uncurry (+)) [(1,2), (3,4), (5,6)]
-- Result: [3, 7, 11]
How does this work? Let's consider the types:
(+) :: Num a => a -> a -> a
uncurry :: (a -> b -> c) -> (a, b) -> c
map :: (a -> b) -> [a] -> [b]
As you may already know, in Haskell, the normal way of doing multi-argument functions is by **currying* them. The type of (+) reflects this: conceptually it takes one argument and produces a function that then takes the "second" argument to produce the final result.
uncurry takes such a curried two-argument function and adapts it to work on a pair. It's trivial to implement:
uncurry :: (a -> b -> c) -> (a, b) -> c
uncurry f (a, b) = f a b
Funnily enough, the uncurry function is curried, so its partial application uncurry (+) has type Num a => (a, a) -> a. This would then be a function that takes a pair of numbers and adds them.
And map simply applies a function to every element of a list, collecting the individual results into a list. Plug them all together and that's a solution.
In F# at some point I have many lists (the actual number of them differs for input data) and I want to make an aggregation over all those lists (let say addition for simplification). So what I want to achieve is the same what List.map2 or List.map3 does but for bigger number of lists.
How can I approach it? I was wondering if this is possible to do with List.scan?
You can use List.reduce and do something like this:
> let lists = [[1;2;3]; [1;2;3]; [1;2;3]]
val lists : int list list = (...)
> lists |> List.reduce (List.map2 (+));;
val it : int list = [3; 6; 9]
What does this do?
List.reduce takes a list of values (here the value is int list) and it aggregates them into a single value using a function that says how to merge two values. So in this case, we need to give it a function int list -> int list -> int list and it will call it on the first and the second list, then on the result and the third list (and so on).
The argument List.map2 (+) is a function of the right type - it takes two lists and performs pairwise sum of the two lists. This is really just a shortcut for writing something like:
lists |> List.reduce (fun list1 list2 ->
List.map2 (fun a b -> a + b) list1 list2)
I've been tasked with creating a Haskell program that contains a definition for a polymorphic datatype Bag and some simple functions, such as, converting a list to a bag and checking if two bags are the same.
My problem is I'm new to Haskell, so I'm not sure how to use Bags. Can anyone point me in the direction of some resources to do with Bags?
You can start by reading about algebraic data types.
First try to implement a simple algebraic data type like tree and then you can go and implement your own Bag data type. If you have any problems you can always ask here.
If this is not a homework then you can use already implemented Bags or use Data.Map to implement the same.
I have given the definition using Data.Map to compare your implementation which I suppose you would be writing using your own algebraic data types.
import qualified Data.Map as M
import Data.Map (Map)
newtype Bag a = Bag (Map a Int)
deriving (Show,Eq)
empty :: Bag a
empty = Bag $ M.empty
singleton :: a -> Bag a
singleton a = Bag $ M.singleton a 1
fromList :: (Ord a) => [a] -> Bag a
fromList = foldl f empty
where
f (Bag map) x = Bag $ M.insertWith (+) x 1 map
toList :: Bag a -> [a]
toList (Bag m) = concatMap f $ M.toList m
where f (a,b) = replicate b a
I have defined some very basic functions, but you can do things which you asked and a lot more, like
*Main> let x = fromList [1,2,3,2,2,1]
*Main> x
Bag (fromList [(1,2),(2,3),(3,1)])
*Main> let y = fromList [1,1,2,2,2,3]
*Main> y
Bag (fromList [(1,2),(2,3),(3,1)])
*Main> x==y
True