How to create a function to zip and unzip two lists as tupled lists in Standard ML?
Example:
unzip [[1,4],[2,5],[3,6]] -> [1,2,3] [4,5,6]
zip [1,2,3] [0,2,4] -> [[1,0],[2,2],[3,4]]
I figured out what I was doing wrong.
Here's the code:
fun zip nil nil = nil
| zip nil l = l
| zip l nil = l
| zip (h::t) (k::l) = [h,k]::(zip t l)
fun mapcan(f,nil) = nil | mapcan(f,h::t) = (f h)#(mapcan(f,t))
fun unzip (l) = if (l = nil) then nil else [(map head l),(mapcan tail l)]
Unzipping is slightly more difficult. We need map functions that select the first and second elements of a two-element list over the zipped list. Since the problem is somewhat under-specified by the example, we will put the rest of the longer list into the first list. To avoid problems with the empty tails for the shorter list, we use the mapcan function that appends the tail lists.
It is usually not a good idea to use head and tail, but instead to use pattern matching. You can encode unzip a bit more elegantly as follows:
fun unzip l =
case l
of nil => (nil, nil)
| (a,b)::tl =>
let val (l1, l2) = unzip tl
in (a::l1, b::l2) end
Also as one of the commenters above mentioned, zip and unzip typically work on pairs of lists, and lists of pairs respectively.
There is absolutely no need for the lexical scoping introduced by the let statement. By defining the projection functions, one can actually get a far more concise and elegant representation :
fun fst p =
case p of
(x,_) => x
fun snd p =
case p of
(_,y) => y
fun unzip lp =
case lp of
[] => ([], [])
| (x,y) :: lp' => (x :: (fst (unzip lp')), y :: (snd (unzip lp')))
There is good reason why this works, which is that Type-Inference from the SML compiler is strong enough to deduce the types of the terms from the case statements and the cons statements. The projection functions are deduced before, and the CSP for the Type-Constraints is solvable. IMO, this is far more elegant than the solutions presented before with the let statement.
Compiler
Related
I have to write a function that, given two lists, it returns a list of the elements of the first one whose square is present in the second one (sry for my english). I can't do it recursively and i can't use List.filter.
this is what i did:
let lst1= [1;2;3;4;5];;
let lst2= [9;25;10;4];;
let filquadi lst1 lst2 =
let aux = [] in
List.map(fun x -> if List.mem (x*x) lst2 then x::aux else []) lst1;;
It works but it also prints [] when the number doesn't satisfy the if statement:
filquadi lst1 lst2 ;;
- : int list list = [[]; [2]; [3]; []; [5]]
how can I return a list of numbers instead of a list of a list of numbers?
- : int list = [2;3;5]
You can use List.concat to put things together at the end:
List.concat (List.map ...)
As a side comment, aux isn't doing anything useful in your code. It's just a name for the empty list (since OCaml variables are immutable). It would probably be clearer just to use [x] instead of x :: aux.
As another side comment, this is a strange sounding assignment. Normally the reason to forbid use of functions from the List module is to encourage you to write your own recursive solution (which indeed is educational). I can't see offhand a reason to forbid the use of recursion, but it's interesting to combine functions from List in different ways.
Your criteria don't say you can't use List.fold_left or List.rev, so...
let filter lst1 lst2 =
List.fold_left
(fun init x ->
if List.mem (x * x) lst2 then x::init
else init)
[] lst1
|> List.rev
We start with an empty list, and as we fold over the first list, add the current element only if that element appears in the second list. Because this results in a list that's reversed from its original order, we then reverse that.
If you're not supposed to use recursion, this is technically cheating, because List.fold_left works recursively, but then so does basically anything working with lists. Reimplementing the List module's functions is going to involve a lot of recursion, as can be seen from reimplementing fold_left and filter.
let rec fold_left f init lst =
match lst with
| [] -> init
| x::xs -> fold_left f (f init x) xs
let rec filter f lst =
match lst with
| [] -> []
| x::xs when f x -> x :: filter f xs
| _::xs -> filter f xs
I'm trying to learn haskell by solving some online problems and training exercises.
Right now I'm trying to make a function that'd remove adjacent duplicates from a list.
Sample Input
"acvvca"
"1456776541"
"abbac"
"aabaabckllm"
Expected Output
""
""
"c"
"ckm"
My first though was to make a function that'd simply remove first instance of adjacent duplicates and restore the list.
module Test where
removeAdjDups :: (Eq a) => [a] -> [a]
removeAdjDups [] = []
removeAdjDups [x] = [x]
removeAdjDups (x : y : ys)
| x == y = removeAdjDups ys
| otherwise = x : removeAdjDups (y : ys)
*Test> removeAdjDups "1233213443"
"122133"
This func works for first found pairs.
So now I need to apply same function over the result of the function.
Something I think foldl can help with but I don't know how I'd go about implementing it.
Something along the line of
removeAdjDups' xs = foldl (\acc x -> removeAdjDups x acc) xs
Also is this approach the best way to implement the solution or is there a better way I should be thinking of?
Start in last-first order: first remove duplicates from the tail, then check if head of the input equals to head of the tail result (which, by this moment, won't have any duplicates, so the only possible pair is head of the input vs. head of the tail result):
main = mapM_ (print . squeeze) ["acvvca", "1456776541", "abbac", "aabaabckllm"]
squeeze :: Eq a => [a] -> [a]
squeeze (x:xs) = let ys = squeeze xs in case ys of
(y:ys') | x == y -> ys'
_ -> x:ys
squeeze _ = []
Outputs
""
""
"c"
"ckm"
I don't see how foldl could be used for this. (Generally, foldl pretty much combines the disadvantages of foldr and foldl'... those, or foldMap, are the folds you should normally be using, not foldl.)
What you seem to intend is: repeating the removeAdjDups, until no duplicates are found anymore. The repetition is a job for
iterate :: (a -> a) -> a -> [a]
like
Prelude> iterate removeAdjDups "1233213443"
["1233213443","122133","11","","","","","","","","","","","","","","","","","","","","","","","","","","",""...
This is an infinite list of ever reduced lists. Generally, it will not converge to the empty list; you'll want to add some termination condition. If you want to remove as many dups as necessary, that's the fixpoint; it can be found in a very similar way to how you implemented removeAdjDups: compare neighbor elements, just this time in the list of reductions.
bipll's suggestion to handle recursive duplicates is much better though, it avoids unnecessary comparisons and traversing the start of the list over and over.
List comprehensions are often overlooked. They are, of course syntactic sugar but some, like me are addicted. First off, strings are lists as they are. This functions could handle any list, too as well as singletons and empty lists. You can us map to process many lists in a list.
(\l -> [ x | (x,y) <- zip l $ (tail l) ++ " ", x /= y]) "abcddeeffa"
"abcdefa"
I don't see either how to use foldl. It's maybe because, if you want to fold something here, you have to use foldr.
main = mapM_ (print . squeeze) ["acvvca", "1456776541", "abbac", "aabaabckllm"]
-- I like the name in #bipll answer
squeeze = foldr (\ x xs -> if xs /= "" && x == head(xs) then tail(xs) else x:xs) ""
Let's analyze this. The idea is taken from #bipll answer: go from right to left. If f is the lambda function, then by definition of foldr:
squeeze "abbac" = f('a' f('b' f('b' f('a' f('c' "")))
By definition of f, f('c' "") = 'c':"" = "c" since xs == "". Next char from the right: f('a' "c") = 'a':"c" = "ac" since 'a' != head("c") = 'c'. f('b' "ac") = "bac" for the same reason. But f('b' "bac") = tail("bac") = "ac" because 'b' == head("bac"). And so forth...
Bonus: by replacing foldr with scanr, you can see the whole process:
Prelude> squeeze' = scanr (\ x xs -> if xs /= "" && x == head(xs) then tail(xs) else x:xs) ""
Prelude> zip "abbac" (squeeze' "abbac")
[('a',"c"),('b',"ac"),('b',"bac"),('a',"ac"),('c',"c")]
I am new to Haskell, and I want to make 1 function that will take two lists and merge then together, and then sort the combined list from smallest to biggest.
this should be done in the command line without using modules.
This is what i currently have, I am having trouble getting the "sortList" function to work, and also I do not know how to combine these 3 lines into 1 function.
let combineList xs ys = xs++ys
let zs = combineList xs ys
let sortList (z:zs) = if (head zs) < z then (zs:z) else (z:(sortList zs))
How to sort list in ghci:
Prelude> :m + Data.List
Prelude Data.List> sort [1,4,2,0]
[0,1,2,4]
About your functions
let combineList xs ys = xs++ys
What is a point to create another alias for append function? But if you're really wants one - it could be defined like let combineList = (++).
let zs = combineList xs ys
It makes no sense because xs and ys are unknown outside of your combineList.
let sortList (z:zs) = if (head zs) < z then (zs:z) else (z:(sort zs))
This definition is not valid because it doesn't cover and empty list case and (zs:z) produces infinite type and sort is not defined yet. And you can get head of zs just by another pattern matching. And maybe you don't wanna to make another recursive call in the then part of if statement. And finally I should admit that this sorting algorithm doesn't work at all.
It's a bit awkward to define a sorting function within the ghci. I thing the easiest way to do it would be to write the sorting function in a file, and then loading it into ghci. For instance, you could write this concise (though not in-place!) version of quicksort in a file called sort.hs (taken from the HaskellWiki):
quicksort :: Ord a => [a] -> [a]
quicksort [] = []
quicksort (p:xs) = (quicksort lesser) ++ [p] ++ (quicksort greater)
where
lesser = filter (< p) xs
greater = filter (>= p) xs
and load it into ghci:
> :l sort.hs
If you really want to define the function in ghci, you can do something like this (from the Haskell user's guide):
> :{
> let { quicksort [] = []
> ; quicksort (p:xs) = (quicksort (filter (< p) xs)) ++ [p] ++ (quicksort (filter (>= p) xs))
> }
> :}
once this is defined, you can do
> let combineAndSort xs ys = quicksort (xs ++ ys)
As another answer already explained, it would of course be quicker to just import sort from Data.List, but it is definitely a good exercise to do it manually.
Your question suggests that you are a bit confused about the scope of variables in Haskell. In this line
> let combineList xs ys = xs++ys
you introduce the variables xs and ys. Mentioning them to the left of the equals sign just means that combineList takes two variables, and in the body of that function, you are going to refer to these variables as xs and ys. It doesn't introduce the names outside of the function, so the next line
> let zs = combineList xs ys
doesn't really make sense, because the names xs and ys are only valid within the scope of combineList. To make zs have a value, you need to give combineList some concrete arguments, eg.:
> let zs = combineList [2,4,6] [1,3,5] --> [2,4,6,1,3,5]
But since the body of combineList is so simple, it would actually be easier to just do:
> let zs = [2,4,6] ++ [1,3,5] --> [2,4,6,1,3,5]
The last line is
> let sortList (z:zs) = if (head zs) < z then (zs:z) else (z:(sortList zs))
I think this line has confused you a lot, because there are quite a lot of different errors here. The answer by ДМИТРИЙ МАЛИКОВ mentions most of them, I would encourage you to try understand each of the errors he mentions.
So i'm new to sml and am trying to understand the ins/out out of it. Recently i tried creating a filter which takes two parameters: a function (that returns a boolean), and a list of values to run against the function. What the filter does is it returns the list of values which return true against the function.
Code:
fun filter f [] = [] |
filter f (x::xs) =
if (f x)
then x::(filter f xs)
else (filter f xs);
So that works. But what i'm trying to do now is just a return a tuple that contains the list of true values, and false. I'm stuck on my conditional and I can't really see another way. Any thoughts on how to solve this?
Code:
fun filter2 f [] = ([],[]) |
filter2 f (x::xs) =
if (f x)
then (x::(filter2 f xs), []) (* error *)
else ([], x::(filter2 f xs)); (* error *)
I think there are several ways to do this.
Reusing Filter
For instance, we could use a inductive approach based on the fact that your tuple would be formed by two elements, the first is the list of elements that satisfy the predicate and the second the list of elements that don't. So, you could reuse your filter function as:
fun partition f xs = (filter f xs, filter (not o f) xs)
This is not the best approach, though, because it evaluates the lists twice, but if the lists are small, this is quite evident and very readable.
Folding
Another way to think about this is in terms of fold. You could think that you are reducing your list to a tuple list, and as you go, you split your items depending on a predicate. Somwewhat like this:
fun parition f xs =
let
fun split x (xs,ys) =
if f x
then (x::xs,ys)
else (xs, x::ys)
val (trueList, falseList) = List.foldl (fn (x,y) => split x y)
([],[]) xs
in
(List.rev trueList, List.rev falseList)
end
Parition
You could also implement your own folding algorithm in the same way as the List.parition method of SML does:
fun partition f xs =
let
fun iter(xs, (trueList,falseList)) =
case xs of
[] => (List.rev trueList, List.rev falseList)
| (x::xs') => if f x
then iter(xs', (x::trueList,falseList))
else iter(xs', (trueList,x::falseList))
in
iter(xs,([],[]))
end
Use SML Basis Method
And ultimately, you can avoid all this and use SML method List.partition whose documentation says:
partition f l
applies f to each element x of l, from left to right, and returns a
pair (pos, neg) where pos is the list of those x for which f x
evaluated to true, and neg is the list of those for which f x
evaluated to false. The elements of pos and neg retain the same
relative order they possessed in l.
This method is implemented as the previous example.
So I will show a good way to do it, and a better way to do it (IMO). But the 'better way' is just for future reference when you learn:
fun filter2 f [] = ([], [])
| filter2 f (x::xs) = let
fun ftuple f (x::xs) trueList falseList =
if (f x)
then ftuple f xs (x::trueList) falseList
else ftuple f xs trueList (x::falseList)
| ftuple _ [] trueList falseList = (trueList, falseList)
in
ftuple f (x::xs) [] []
end;
The reason why yours does not work is because when you call x::(filter2 f xs), the compiler is naively assuming that you are building a single list, it doesn't assume that it is a tuple, it is stepping into the scope of your function call. So while you think to yourself result type is tuple of lists, the compiler gets tunnel vision and thinks result type is list. Here is the better version in my opinion, you should look up the function foldr if you are curious, it is much better to employ this technique since it is more readable, less verbose, and much more importantly ... more predictable and robust:
fun filter2 f l = foldr (fn(x,xs) => if (f x) then (x::(#1(xs)), #2(xs)) else (#1(xs), x::(#2(xs)))) ([],[]) l;
The reason why the first example works is because you are storing default empty lists that accumulate copies of the variables that either fit the condition, or do not fit the condition. However, you have to explicitly tell SML compiler to make sure that the type rules agree. You have to make absolutely sure that SML knows that your return type is a tuple of lists. Any mistake in this chain of command, and this will result in failure to execute. Hence, when working with SML, always study your type inferences. As for the second one, you can see that it is a one-liner, but I will leave you to research that one on your own, just google foldr and foldl.
I have a chained list like
["root", "foo", "bar", "blah"]
And I'd like to convert it to a list of tuples, using adjacent pairs. Like so
[("root", "foo"), ("foo", "bar"), ("bar", "blah")]
At the moment, I'm using this to do it:
zipAdj x = tail (zip ("":x) (x++[""]))
However, I don't really like this method. Can anyone think of a better way? If it's glaringly obvious I apologise, I'm fairly new to Haskell.
Okay, here's the comment as an answer:
Just zipAdj x = zip x $ tail x will suffice. zip stops upon reaching the end of the shorter of the two lists, so this simply pairs each item in the list with its successor, which seems to be all you want.
And for the sake of explaining the pointless version: zip <*> tail uses the Applicative instance for "functions from some type", which basically amounts to a lightweight inline Reader monad--in this case the list is the "environment" for the Reader. Usually this just obfuscates matters but in this case it almost makes it clearer, assuming you know to read (<*>) here as "apply both of these to a single argument, then apply the first to the second".
One possible solution:
pairs [] = []
pairs (x:[]) = []
pairs (x:y:zs) = (x, y) : pairs (y : zs)
Definitely not as small as yours, and can probably be optimized quite a bit.
It's possible to generalize the zipAdj in the question to work with arbitrary Traversable containers. Here's how we'd do it if we wanted the extra element on the front end:
import Data.Traversable
pairDown :: Traversable t => a -> t a -> t (a, a)
pairDown x = snd . mapAccumL (\old new -> (new, (old,new))) x
*Pairing> take 10 $ pairDown 0 [1..]
[(0,1),(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,8),(8,9),(9,10)]
*Pairing> pairDown 0 [1..10]
[(0,1),(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,8),(8,9),(9,10)]
To stick the extra element on the end, we can use mapAccumR:
import Data.Traversable
pairUp :: Traversable t => t a -> a -> t (a, a)
pairUp xs x = snd $ mapAccumR (\old new -> (new, (new,old))) x xs
This effectively traverses the container backwards.
*Pairing> pairUp [0..10] 11
[(0,1),(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,8),(8,9),(9,10),(10,11)]
*Pairing> take 10 $ pairUp [0..] undefined
[(0,1),(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,8),(8,9),(9,10)]
It's impossible to generalize the apparently-desired function in quite this fashion, but it's possible to generalize it a bit differently:
import Data.Foldable
import Prelude hiding (foldr)
pairAcross :: Foldable f => f a -> [(a,a)]
pairAcross xs = foldr go (const []) xs Nothing
where
go next r Nothing = r (Just next)
go next r (Just prev) = (prev, next) : r (Just next)
This gives
*Pairing> pairAcross [1..10]
[(1,2),(2,3),(3,4),(4,5),(5,6),(6,7),(7,8),(8,9),(9,10)]