I am new to Haskell.
I am trying to write a program which given a list as an input replicates each element of list k times, where k = position of element in list.
e.g. replic[5,6,7] gives [[5],[6,6],[7,7,7]].
Another condition is solution has to use map function.
Till now code I have written is :
replic [] = []
replic (x:xs) = map (replicate 2 ) [x] ++ replic xs
This replicates every element twice as replicate has input parameter 2.
What I need is replicate function should be given input as 1 ,2 ,3 in consecutive calls. So I need a counter. How can I use the counter there or do anything else that will give me position of element?
Expanding on Satvik, the notation
[1..]
gives you an infinite list of numbers counting up.
The function zip associates allows you to merge two lists into a list of tuples
zip :: [a] -> [b] -> [(a,b)]
for example
> zip [1..] [5,6,7]
[(1,5),(2,6),(3,7)]
this code associates each value in the list with its position in the list
now
replicate :: Int -> a -> [a]
repeats a value an arbitrary number of times. Given these two components, we can design a simple function
replic xs = map (\(a,b) -> replicate a b) (zip [1..] xs)
which I would write pointfree as
replic :: [a] -> [[a]]
replic = map (uncurry replicate) . zip [1..]
this does exactly what you want
> replic [5,6,7]
[[5],[6,6],[7,7,7]]
There are many ways of doing this
Here is a solution similar to what you tried to do. zipping the list with list [1..] gives you the counter you wanted.
replic = repl . zip [1..]
repl [] = []
repl ((x,y):xs) = (replicate x y) : (repl xs)
Another solution using just map
replic = map f . zip [1..]
where
f (c,l) = replicate c l
If you don't like idea of using zip you can also use mapAccumL
import Data.List
replic = snd . mapAccumL f 1
where
f a v = (a+1,replicate a v)
Usually you would write:
replic = zipWith replicate [1..]
Now you can write your own zipWith yourself using map:
zipWith' f xs ys = map (uncurry f) $ zip xs ys
Note that you don't necessarily need an index, e.g.
import Data.List
replic xs = reverse $ transpose (tail $ inits $ reverse xs)
You can do something like this with map when using explicit recursion:
replic = f . map return where
f [] = []
f (x:xs) = x : f (map (\(x:xs) -> x:x:xs) xs)
Related
So I'm trying to make a function "rot" which takes a string and returns a list of strings with all possible rotations, e.g rot "abc" returns ["abc", "bca", cab"], seems very simple to do in other languages but I'm a newbie at haskell so I can't think of a way to do it. This is what I have so far:
rot :: [Char] -> [[Char]]
rot word =
let
lst = [tail word ++ [head word]]
in
lst
main = do
print(rot "abc")
It returns me "bca" as expected, but I would like a way to find all rotations and store it in a list.
Here's an example in python
def rot(word):
lst = []
for i in range(len(word)):
newWord1 = word[0:i]
newWord2 = word[i:]
newWordResult = newWord2 + newWord1
lst.append(newWordResult)
return lst
Well, you can more or less directly translate your Python code. Recursion is customarily used in functional programming instead of iteration, and it's more convenient to count from length word down to zero. Other than that, it's pretty much the same:
rot word =
let loop 0 lst = lst
loop i lst =
let newWord1 = take (i-1) word
newWord2 = drop (i-1) word
newWordResult = newWord2 ++ newWord1
in loop (i-1) (newWordResult : lst)
in loop (length word) []
One can make use of the tails and inits of a list:
Prelude Data.List> tails "abc"
["abc","bc","c",""]
Prelude Data.List> inits "abc"
["","a","ab","abc"]
we thus can use this with:
import Data.List(inits, tails)
rotated :: [a] -> [[a]]
rotated xs = [x ++ y | (x#(_:_), y) <- zip (tails xs) (inits xs)]
This produces:
Prelude Data.List> rotated "abc"
["abc","bca","cab"]
Prelude Data.List> rotated [1,4,2,5]
[[1,4,2,5],[4,2,5,1],[2,5,1,4],[5,1,4,2]]
Prelude Data.List> rotated [1.0,3.0,0.0,2.0]
[[1.0,3.0,0.0,2.0],[3.0,0.0,2.0,1.0],[0.0,2.0,1.0,3.0],[2.0,1.0,3.0,0.0]]
or as #Iceland_jack says, we can use the ParallelListComp extension to allow iterating over two lists in parallel in list comprehension without the explicit use of zip:
{-# LANGUAGE ParallelListComp #-}
import Data.List(inits, tails)
rotated :: [a] -> [[a]]
rotated xs = [x ++ y | x#(_:_) <- tails xs | y <- inits xs]
This is, simply,
rotations xs = map (take n) . take n
. tails $ xs ++ xs
where
n = length xs
It is customary to avoid length if at all possible, though here it leads to a bit more convoluted code(*) (but more often than not it leads to a simpler, cleaner code that is more true to the true nature of the problem),
rotations2 xs = map (zipWith (\a b -> b) xs)
. zipWith (\a b -> b) xs
. tails $ xs ++ xs
Testing, we get
> rotations "abcd"
["abcd","bcda","cdab","dabc"]
> rotations2 "abcd"
["abcd","bcda","cdab","dabc"]
> take 4 . map (take 4) $ rotations2 [1..]
[[1,2,3,4],[2,3,4,5],[3,4,5,6],[4,5,6,7]]
(*) edit Actually, it probably merits its own name,
takeLength :: [a] -> [b] -> [b]
takeLength = zipWith (\a b -> b)
rotations2 xs = map (takeLength xs)
. takeLength xs
. tails $ xs ++ xs
I am trying to split a string into a list of sequences that are substrings of this string. It's a bit hard to explain but I will give you an example so you can understand what I am looking for.
From this string "123456789", I would like to obtain a list like so:
["123", "234, "345, ..., "789", "891", "912"]
At the moment, I only have a function that splits a string into a list of n parts of this string:
splitList :: Int -> [a] -> [[a]]
splitList _ [] = []
splitList n xs = as : splitList n bs
where (as,bs) = splitAt n xs
I would just use a combination of take and drop, with a list comprehension:
splitList :: Int -> [a] -> [[a]]
splitList n xs = [take n $ drop i $ xs ++ xs | i <- [0..(length xs - 1)]]
(the xs ++ xs is only there to get the "cycling" affect, it could be tuned to only add on the first (n-1) elements but I believe Haskell's laziness should mean there is no efficiency loss in doing it this way)
I would do it this way:
import Data.List
splitList n xs = zipWith const chunks xs where
chunks = map (take n) . tails . cycle $ xs
This should have complexity O(m*n), where m is the length of xs and n is the size of each chunk; naively it seems as though it should be hard to do better than that, since that's the size of the output. It also neatly handles a number of awkward edge cases, including working sensibly on infinite list inputs.
If you haven't seen the zipWith const trick before, it's definitely one worth adding to your arsenal. It lets you do roughly the same thing as take (length xs) ys, but without actually computing length xs beforehand.
splitList :: Int -> [a] -> [[a]]
splitList n xs = zipWith const (map (take n) . tails . cycle $ xs) xs
-- splitList n = zipWith const =<< map (take n) . tails . cycle
-- splitList n = map (take n) . tails . cycle >>= zipWith const
does the job, and also works on infinite input, i.e. is properly lazy.
zipWith const is used instead of length and take, counting in list elements instead of numbers.
The pointfree variants are even readable / illuminating somewhat as to what is going on here.
(forgot to mention, tails are from Data.List).
Suppose we have list [1,2,3,4].
I want to take every pair of consecutive elements (i.e. (1,2),(2,3),(3,4)), apply them to some function, and return list which consist of results of this function.
I don't quite understand, how to do this on haskell, since we don't actually have loops and arrays here.
Here are some ways you could try to solve this. The first step will be to get the pairs and the second will be applying the function to the pairs. One way to do the first step is with a recursive function. Now in Haskell lists are made using [] and :, with [1,2,3] being syntactic sugar for 1:(2:(3:[])). So let us write our function:
window [] = []
window [a] = []
window [a,b] = [(a,b)]
window (a:b:r) = (a,b):window (b:r)
Another way we could do this is with the function zip. Recall that this takes two lists, pairs up their elements, and ends the list when either input ends.
window [] = []
window xs = zip xs (tail xs)
The second step is to apply our function to the pairs. We can do this with map (uncurry f). All together:
onWindow f = map (uncurry f) . window
There's several approaches that could work here.
You could use recursion:
mapCons :: (a -> a -> b) -> [a] -> [b]
-- input has at least two elements
mapCons f (a0:a1:as) =
-- use them to compute the head of the output
f a0 a1 :
-- reuse the second element to compute the tail of the output
mapCons f (a1:as)
-- input has less than two elements, so output is the empty list
mapCons _ _ = []
Alternately, zip converts a pair of lists into a list of pairs:
λ zip [1..10] ['a'..'z']
[(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e'),(6,'f'),(7,'g'),(8,'h'),(9,'i'),(10,'j')]
This gives a way to generate all the consecutive pairs in a list by zipping a list with its own tail:
λ zip [1..10] ['a'..'z']
[(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e'),(6,'f'),(7,'g'),(8,'h'),(9,'i'),(10,'j')]
You could then use map to run your function on each pair in the list
λ map (\(a,b) -> 10*a + b) $ zip [0..9] (tail [0..9])
[1,12,23,34,45,56,67,78,89]
This is a common enough pattern that there's a function that combines map and zip: zipWith:
λ :t zipWith
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
λ zipWith (\a b -> 10*a + b) [0..9] (tail [0..9])
[1,12,23,34,45,56,67,78,89]
says that we want to filter out all the odd one in a list.
odd' (i,n) = odd i
unbox (i,n) = n
f :: [Int] -> [Int]
f lst = map unbox $ filter odd' $ zip [1..] lst
*Main> f [1,2,3,4]
[1,3]
it has the unpleasant boxing and unboxing.
can we change the way we think this problem and eliminate boxing and unboxing?
#user3237465 list comprehension is indeed a good way of thinking this sort of problem.
as well as function composition. well, I think we won't get rid of "wrapping the original list to [(index,value)] form and then unwrap it" without writing a special form like #Carsten König provided.
Or have a function that give out one value's index given the list and the value. like filter (odd . getindex) xs
and maybe that's why clojure made it's pattern matching strong enough to get value in complex structure.
you can always rewrite the function if you want - this comes to mind:
odds :: [a] -> [a]
odds (x:_:xs) = x : odds xs
odds [x] = [x]
odds _ = []
aside from this both you don't need odd' and unbox:
odd' is just odd . fst
unbox is just snd
You can write this as
f xs = [x | (i, x) <- zip [0..] xs, even i]
or
f = snd . foldr (\x ~(o, e) -> (e, x : o)) ([], [])
or
import Data.Either
f = lefts . zipWith ($) (cycle [Left, Right])
I want to create a simple (involving sets and lists) function that can do the following, and i'm not sure where to start.
split:: [(a,b)] -> ([a],[b])
Let's take it step by step. The two cases for the function are:
split [] = ???
split ((a,b):ps) = ???
One case is easy enough.
split [] = ([], [])
For the other one, we have to use the function recursively, someway
split ((a,b):ps) = ???? where
(as, bs) = split ps
I think it's easy to see that the solution is
split ((a,b):ps) = (a:as, b:bs) where
(as, bs) = split ps
In addition to Guido's solution, there is more than one way to do it in haskell.
Please take a look at fst and snd, which takes the first / second element out of a pair, respectively.
GHCi> :t fst
fst :: (a, b) -> a
GHCi> :t snd
snd :: (a, b) -> b
You should be familiar with map if you are playing with functional programming languages, which takes a function and a list, applies the function on every element of that list, and gives you all the results in another list:
GHCi> :t map
map :: (a -> b) -> [a] -> [b]
Given a list of pairs, you want two lists, one contains all first elements in order, and the other contains all second elements:
GHCi> let split xs = (map fst xs, map snd xs)
GHCi> split [(1,2),(3,4),(5,6)]
([1,3,5],[2,4,6])
GHCi>
One step further, as #jozefg has pointed out in the comment, that this method is not efficient as #Guido 's one, but we can make some changes to improve it (which is exactly what #Guido 's solution):
Now it's time to take a look at how map is implemented here
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
so we can try to change our split a little:
we still need the base case, (i.e. what if xs is empty):
split [] = ([], [])
split ls = (map fst ls, map snd ls) -- attention!
and we break the list into head and tail, just like map:
split (x:xs) = (fst x: map fst xs, snd x: map snd xs)
Now we can do a pattern matching, (a,b) = x, so we don't have to call two individual functions to break a pair into two:
split (x:xs) = (a: map fst xs, b: map snd xs)
where (a,b) = x
Compare the code here with the line I commented "attention!", have you realized that if we know the result of (map fst xs, map snd xs), we can simply reuse that result to speed up. Luckily, we already have split ls = (map fst ls, map snd ls)!
Using this fact, we finally come up with this version:
split [] = ([], [])
split (x:xs) = (a:as , b:bs)
where (a,b) = x
(as,bs) = split xs
So there are essentially the same! (but as you can see, the last version we have is more efficient.)