Related
I'm playing around with Haskell, mostly trying to learn some new techniques to solve problems. Without any real application in mind I came to think about an interesting thing I can't find a satisfying solution to. Maybe someone has any better ideas?
The problem:
Let's say we want to generate a list of Ints using a starting value and a list of Ints, representing the pattern of numbers to be added in the specified order. So the first value is given, then second value should be the starting value plus the first value in the list, the third that value plus the second value of the pattern, and so on. When the pattern ends, it should start over.
For example: Say we have a starting value v and a pattern [x,y], we'd like the list [v,v+x,v+x+y,v+2x+y,v+2x+2y, ...]. In other words, with a two-valued pattern, next value is created by alternatingly adding x and y to the number last calculated.
If the pattern is short enough (2-3 values?), one could generate separate lists:
[v,v,v,...]
[0,x,x,2x,2x,3x, ...]
[0,0,y,y,2y,2y,...]
and then zip them together with addition. However, as soon as the pattern is longer this gets pretty tedious. My best attempt at a solution would be something like this:
generateLstByPattern :: Int -> [Int] -> [Int]
generateLstByPattern v pattern = v : (recGen v pattern)
where
recGen :: Int -> [Int] -> [Int]
recGen lastN (x:[]) = (lastN + x) : (recGen (lastN + x) pattern)
recGen lastN (x:xs) = (lastN + x) : (recGen (lastN + x) xs)
It works as intended - but I have a feeling there is a bit more elegant Haskell solution somewhere (there almost always is!). What do you think? Maybe a cool list-comprehension? A higher-order function I've forgotten about?
Separate the concerns. First look a just a list to process once. Get that working, test it. Hint: “going through the list elements with some accumulator” is in general a good fit for a fold.
Then all that's left to is to repeat the list of inputs and feed it into the pass-once function. Conveniently, there's a standard function for that purpose. Just make sure your once-processor is lazy enough to handle the infinite list input.
What you describe is
foo :: Num a => a -> [a] -> [a]
foo v pattern = scanl (+) v (cycle pattern)
which would normally be written even as just
foo :: Num a => a -> [a] -> [a]
foo v = scanl (+) v . cycle
scanl (+) v xs is the standard way to calculate the partial sums of (v:xs), and cycle is the standard way to repeat a given list cyclically. This is what you describe.
This works for a pattern list of any positive length, as you wanted.
Your way of generating it is inventive, but it's almost too clever for its own good (i.e. it seems overly complicated). It can be expressed with some list comprehensions, as
foo v pat =
let -- the lists, as you describe them:
lists = repeat v :
[ replicate i 0 ++
[ y | x <- [p, p+p ..]
, y <- map (const x) pat ]
| (p,i) <- zip pat [1..] ]
in
-- OK, so what do we do with that? How do we zipWith
-- over an arbitrary amount of lists?
-- with a fold!
foldr (zipWith (+)) (repeat 0) lists
map (const x) pat is a "clever" way of writing replicate (length pat) x. It can be further shortened to x <$ pat since (<$) x xs == map (const x) xs by definition. It might seem obfuscated, until you've become accustomed to it, and then it seems clear and obvious. :)
Surprised noone's mentioned the silly way yet.
mylist x xs = x : zipWith (+) (mylist x xs) (cycle xs)
(If you squint a bit you can see the connection to scanl answer).
When it is about generating series my first approach would be iterate or unfoldr. iterate is for simple series and unfoldr is for those who carry kind of state but without using any State monad.
In this particular case I think unfoldr is ideal.
series :: Int -> [Int] -> [Int]
series s [x,y] = unfoldr (\(f,s) -> Just (f*x + s*y, (s+1,f))) (s,0)
λ> take 10 $ series 1 [1,1]
[1,2,3,4,5,6,7,8,9,10]
λ> take 10 $ series 3 [1,1]
[3,4,5,6,7,8,9,10,11,12]
λ> take 10 $ series 0 [1,2]
[0,1,3,4,6,7,9,10,12,13]
It is probably better to implement the lists separately, for example the list with x can be implement with:
xseq :: (Enum a, Num a) => a -> [a]
xseq x = 0 : ([x, x+x ..] >>= replicate 2)
Whereas the sequence for y can be implemented as:
yseq :: (Enum a, Num a) => a -> [a]
yseq y = [0,y ..] >>= replicate 2
Then you can use zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] to add the two lists together and add v to it:
mylist :: (Enum a, Num a) => a -> a -> a -> [a]
mylist v x y = zipWith ((+) . (v +)) (xseq x) (yseq y)
So for v = 1, x = 2, and y = 3, we obtain:
Prelude> take 10 (mylist 1 2 3)
[1,3,6,8,11,13,16,18,21,23]
An alternative is to see as pattern that we each time first add x and then y. We thus can make an infinite list [(x+), (y+)], and use scanl :: (b -> a -> b) -> b -> [a] -> [b] to each time apply one of the functions and yield the intermediate result:
mylist :: Num a => a -> a -> a -> [a]
mylist v x y = scanl (flip ($)) v (cycle [(x+), (y+)])
this yields the same result:
Prelude> take 10 $ mylist 1 2 3
[1,3,6,8,11,13,16,18,21,23]
Now the only thing left to do is to generalize this to a list. So for example if the list of additions is given, then you can impelement this as:
mylist :: Num a => [a] -> [a]
mylist v xs = scanl (flip ($)) v (cycle (map (+) xs))
or for a list of functions:
mylist :: Num a => [a -> a] -> [a]
mylist v xs = scanl (flip ($)) v (cycle (xs))
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I have a list of lists, for example,
[[1, 1, 1, 1],
[0, 0, 0, 0],
[1, 1, 0, 0],
[0, 0, 1, 1]]
with an even length. Like a square of pixels where black is 1 and white is 0, like a chessboard.
And I want a function that will return 4 lists:
The first list is 2x2 lower right corner would be a list with [1,1,0,0]
The second list is 2x2 upper right corner would be a list with [1,1,0,0]
The third list is 2x2 lower left corner would be a list with [0,0,1,1]
The forth list is 2x2 upper left corner would be a list with [1,1,0,0]
I don't quite yet know how to do this. I expect to receive the 4 lists described above.
The following is working for me, assuming I have now understood your requirements. There may be more sophisticated ways to do this, but this is a simple one which isn't too painful - the key is to write general functions which can take the first/second half of a list of even length. Then the functions you want are built simply from them:
firstHalf :: [a] -> [a]
firstHalf xs
| odd n = error "list needs to have even length"
| otherwise = take h xs
where n = length xs
h = n `div` 2
secondHalf :: [a] -> [a]
secondHalf xs
| odd n = error "list needs to have even length"
| otherwise = drop h xs
where n = length xs
h = n `div` 2
topLeftCorner :: [[a]] -> [a]
topLeftCorner = concatMap firstHalf . firstHalf
topRightCorner :: [[a]] -> [a]
topRightCorner = concatMap secondHalf . firstHalf
bottomLeftCorner :: [[a]] -> [a]
bottomLeftCorner = concat . reverse . map firstHalf . secondHalf
bottomRightCorner :: [[a]] -> [a]
bottomRightCorner = concat . reverse . map secondHalf . secondHalf
allCorners :: [[a]] -> [[a]]
allCorners board = [bottomRightCorner, topRightCorner, bottomLeftCorner, topLeftCorner] <*> [board]
examples of using it, first for your input and then a 6x6 example:
*Main>let board = [[1,1,1,1], [0,0,0,0], [1 ,1, 0,0] , [0, 0, 1,1]]
*Main> allCorners board
[[1,1,0,0],[1,1,0,0],[0,0,1,1],[1,1,0,0]]
*Main> let board = [[1,1,1,1,1,1], [0,0,0,0,0,0], [1 ,1, 0,0,1,1] , [0, 0, 1,1,0,0], [1,1,1,1,1,1], [0,0,0,0,0,0]]
*Main>allCorners board
[[0,0,0,1,1,1,1,0,0],[1,1,1,0,0,0,0,1,1],[0,0,0,1,1,1,0,0,1],[1,1,1,0,0,0,1,1,0]]
As often in functional programming (and indeed in programming in general), the best way to approach a more complex problem is to break it down into smaller ones.
I m a newbie to Haskell. I am pretty good with Imperative languages but not with functional. Haskell is my first as a functional language.
I am trying to figure out, how to get the index of the smallest element in the list where the minimum element is defined by me.
Let me explain by examples.
For example :
Function signature
minList :: x -> [x]
let x = 2
let list = [2,3,5,4,6,5,2,1,7,9,2]
minList x list --output 1 <- is index
This should return 1. Because the at list[1] is 3. It returns 1 because 3 is the smallest element after x (=2).
let x = 1
let list = [3,5,4,6,5,2,1,7,9,2]
minList x list -- output 9 <- is index
It should return 9 because at list[9] is 2 and 2 is the smallest element after 1. x = 1 which is defined by me.
What I have tried so far.
minListIndex :: (Ord a, Num a) => a -> [a] -> a
minListIndex x [] = 0
minListIndex x (y:ys)
| x > y = length ys
| otherwise = m
where m = minListIndex x ys
When I load the file I get this error
• Couldn't match expected type ‘a’ with actual type ‘Int’
‘a’ is a rigid type variable bound by
the type signature for:
minListIndex :: forall a. (Ord a, Num a) => a -> [a] -> a
at myFile.hs:36:17
• In the expression: 1 + length ys
In an equation for ‘minListIndex’:
minListIndex x (y : ys)
| x > y = 1 + length ys
| otherwise = 1 + m
where
m = minListIndex x ys
• Relevant bindings include
m :: a (bound at myFile.hs:41:19)
ys :: [a] (bound at myFile.hs:38:19)
y :: a (bound at myFile.hs:38:17)
x :: a (bound at myFile.hs:38:14)
minListIndex :: a -> [a] -> a (bound at myFile.hs:37:1)
When I modify the function like this
minListIndex :: (Ord a, Num a) => a -> [a] -> a
minListIndex x [] = 0
minListIndex x (y:ys)
| x > y = 2 -- <- modified...
| otherwise = 3 -- <- modifiedd
where m = minListIndex x ys
I load the file again then it compiles and runs but ofc the output is not desired.
What is the problem with
| x > y = length ys
| otherwise = m
?
In short: Basically, I want to find the index of the smallest element but higher than the x which is defined by me in parameter/function signature.
Thanks for the help in advance!
minListIndex :: (Ord a, Num a) => a -> [a] -> a
The problem is that you are trying to return result of generic type a but it is actually index in a list.
Suppose you are trying to evaluate your function for a list of doubles. In this case compiler should instantiate function's type to Double -> [Double] -> Double which is nonsense.
Actually compiler notices that you are returning something that is derived from list's length and warns you that it is not possible to match generic type a with concrete Int.
length ys returns Int, so you can try this instead:
minListIndex :: Ord a => a -> [a] -> Int
Regarding your original problem, seems that you can't solve it with plain recursion. Consider defining helper recursive function with accumulator. In your case it can be a pair (min_value_so_far, its_index).
First off, I'd separate the index type from the list element type altogether. There's no apparent reason for them to be the same. I will use the BangPatterns extension to avoid a space leak without too much notation; enable that by adding {-# language BangPatterns #-} to the very top of the file. I will also import Data.Word to get access to the Word64 type.
There are two stages: first, find the index of the given element (if it's present) and the rest of the list beyond that point. Then, find the index of the minimum of the tail.
-- Find the 0-based index of the first occurrence
-- of the given element in the list, and
-- the rest of the list after that element.
findGiven :: Eq a => a -> [a] -> Maybe (Word64, [a])
findGiven given = go 0 where
go !_k [] = Nothing --not found
go !k (x:xs)
| given == xs = Just (k, xs)
| otherwise = go (k+1) xs
-- Find the minimum (and its index) of the elements of the
-- list greater than the given one.
findMinWithIndexOver :: Ord a => a -> [a] -> Maybe (Word64, a)
findMinWithIndexOver given = go 0 Nothing where
go !_k acc [] = acc
go !k acc (x : xs)
| x <= given = go (k + 1) acc xs
| otherwise
= case acc of
Nothing -> go (k + 1) (Just (k, x)) xs
Just (ix_min, curr_min)
| x < ix_min = go (k + 1) (Just (k, x)) xs
| otherwise = go (k + 1) acc xs
You can now put these functions together to construct the one you seek. If you want a general Num result rather than a Word64 one, you can use fromIntegral at the very end. Why use Word64? Unlike Int or Word, it's (practically) guaranteed not to overflow in any reasonable amount of time. It's likely substantially faster than using something like Integer or Natural directly.
It is not clear for me what do you want exactly. Based on examples I guess it is: find the index of the smallest element higher than x which appears after x. In that case, This solution is plain Prelude. No imports
minList :: Ord a => a -> [a] -> Int
minList x l = snd . minimum . filter (\a -> x < fst a) . dropWhile (\a -> x /= fst a) $ zip l [0..]
The logic is:
create the list of pairs, [(elem, index)] using zip l [0..]
drop elements until you find the input x using dropWhile (\a -> x /= fst a)
discards elements less than x using filter (\a -> x < fst a)
find the minimum of the resulting list. Tuples are ordered using lexicographic order so it fits your problem
take the index using snd
Your function can be constructed out of ready-made parts as
import Data.Maybe (listToMaybe)
import Data.List (sortBy)
import Data.Ord (comparing)
foo :: (Ord a, Enum b) => a -> [a] -> Maybe b
foo x = fmap fst . listToMaybe . take 1
. dropWhile ((<= x) . snd)
. sortBy (comparing snd)
. dropWhile ((/= x) . snd)
. zip [toEnum 0..]
This Maybe finds the index of the next smallest element in the list above the given element, situated after the given element, in the input list. As you've requested.
You can use any Enum type of your choosing as the index.
Now you can implement this higher-level executable specs as direct recursion, using an efficient Map data structure to hold your sorted elements above x seen so far to find the next smallest, etc.
Correctness first, efficiency later!
Efficiency update: dropping after the sort drops them sorted, so there's a wasted effort there; indeed it should be replaced with the filtering (as seen in the answer by Luis Morillo) before the sort. And if our element type is in Integral (so it is a properly discrete type, unlike just an Enum, thanks to #dfeuer for pointing this out!), there's one more opportunity for an opportunistic optimization: if we hit on a succ minimal element by pure chance, there's no further chance of improvement, and so we should bail out at that point right there:
bar :: (Integral a, Enum b) => a -> [a] -> Maybe b
bar x = fmap fst . either Just (listToMaybe . take 1
. sortBy (comparing snd))
. findOrFilter ((== succ x).snd) ((> x).snd)
. dropWhile ((/= x) . snd)
. zip [toEnum 0..]
findOrFilter :: (a -> Bool) -> (a -> Bool) -> [a] -> Either a [a]
findOrFilter t p = go
where go [] = Right []
go (x:xs) | t x = Left x
| otherwise = fmap ([x | p x] ++) $ go xs
Testing:
> foo 5 [2,3,5,4,6,5,2,1,7,9,2] :: Maybe Int
Just 4
> foo 2 [2,3,5,4,6,5,2,1,7,9,2] :: Maybe Int
Just 1
> foo 1 [3,5,4,6,5,2,1,7,9,2] :: Maybe Int
Just 9
I´m new to Haskell.
Let´s say I want to sum up the first n elements of a list with a generated function on my own. I don´t know how to do this with Haskell. I just know how to sum up a whole given list, e.g.
sumList :: [Int] -> Int
sumList [] = 0
sumList (x:xs) = x + sumList xs
In order to sum up the first n elements of a list, for example
take the first 5 numbers from [1..10], which is 1+2+3+4+5 = 15
I thought I could do something like this:
sumList :: Int -> [Int] -> Int
sumList take [] = 0
sumList take (x:xs) = x + take $ sumList xs
But it doesn´t work... What´s wrong?
So you know how to sum up the numbers in a list,
sumList :: [Int] -> Int
sumList [] = 0
sumList (x:xs) = x + sumList xs
and if that list has no more than 5 elements in it, this function will even return the correct result if you indeed intended to sum no more than 5 elements in an argument list. Let's make our expectations explicit by renaming this function,
sumUpToFiveElements :: [Int] -> Int
sumUpToFiveElements [] = 0
sumUpToFiveElements (x:xs) = x + sumUpToFiveElements xs
it won't return the correct result for lists longer than five, but at least the name is right.
Can we fix that? Can we count up to 5? Can we count up to 5 while also advancing along the input list as we do?
sumUpToFiveElements :: Int -> [Int] -> Int
sumUpToFiveElements counter [] = 0
sumUpToFiveElements counter (x:xs) = x + sumUpToFiveElements (counter + 1) xs
This still isn't right of course. We do now count, but for some reason we ignore the counter. What is the right time to react to the counter, if we want no more than 5 elements? Let's try counter == 5:
sumUpToFiveElements :: Int -> [Int] -> Int
sumUpToFiveElements 5 [] = 0
sumUpToFiveElements counter [] = 0
sumUpToFiveElements counter (x:xs) = x + sumUpToFiveElements (counter + 1) xs
But why do we demand the list to also be empty when 5 is reached? Let's not do that:
sumUpToFiveElements :: Int -> [Int] -> Int
sumUpToFiveElements 5 _ = 0 -- the wildcard `_` matches *anything*
sumUpToFiveElements counter [] = 0
sumUpToFiveElements counter (x:xs) = x + sumUpToFiveElements (counter + 1) xs
Success! We now stop counting when 5 is reached! More, we also stop the summation!!
Wait, but what was the initial value of counter? We didn't specify it, so it's easy for a user of our function (that would be ourselves) to err and use an incorrect initial value. And by the way, what is the correct initial value?
Okay, so let's do this:
sumUpToFiveElements :: [Int] -> Int
sumUpToFiveElements xs = go 1 xs -- is 1 the correct value here?
where
go counter _ | counter == 5 = 0
go counter [] = 0
go counter (x:xs) = x + go (counter + 1) xs
Now we don't have that extraneous argument that made our definition so brittle, so prone to a user error.
And now for the punchline:
Generalize! (by replacing an example value with a symbolic one; changing 5 to n).
sumUpToNElements :: Int -> [Int] -> Int
sumUpToNElements n xs = .......
........
Done.
One more word of advice: don't use $ while at the very beginning of your learning Haskell. Use explicit parens.
sumList take (x:xs) = x + take $ sumList xs
is parsed as
sumList take (x:xs) = (x + take) (sumList xs)
This adds together two unrelated numbers, and then uses the result as a function to be called with (sumList xs) as an argument (in other words it's an error).
You probably wouldn't write it that way if you were using explicit parens.
Well you should limit the number of values with a parameter (preferably not take, since
that is a function from the Prelude), and thus limit the numbers.
This limiting in your code is apparently take $ sumList xs which is very strange: in your function take is an Int, and $ will basically write your statement to (x + take) (sumList xs). You thus apparently want to perform a function application with (x + take) (an Int) as function, and sumList xs as argument. But an Int is not a function, so it does not typecheck, nor does it include any logic to limit the numbers.
So basically we should consider three cases:
the empty list in which case the sum is 0;
the number of elements to take is less than or equal to zero, in that case the sum is 0; and
the number of elements to take is greater than 0, in that case we add the head to the sum of taking one element less from the tail.
So a straightforward mapping is:
sumTakeList :: (Integral i, Num n) => i -> [n] -> n
sumTakeList _ [] = 0
sumTakeList t (x:xs) | t <= 0 = 0
| otherwise = x + sumTakeList (t-1) xs
But you do not need to write such logic yourself, you can combine the take :: Int -> [a] -> [a] builtin with the sum :: Num a => [a] -> a functions:
sumTakeList :: Num n => Int -> [n] -> n
sumTakeList t = sum . take t
Now if you need to sum the first five elements, we can make that a special case:
subList5 :: Num n => [n] -> n
sumList5 = sumTakeList 5
A great resource to see what functions are available and how they work is Hoogle. Here is its page on take and the documentation for the function you want.
As you can see, the name take is taken, but it is a function you can use to implement this.
Note that your sumList needs another argument, the number of elements to sum. the syntax you want is something like:
sumList :: Int -> [Int] -> Int
sumList n xs = _ $ take n xs
Where the _ are blanks you can fill in yourself. It's a function in the Prelude, but the type signature is a little too complicated to get into right now.
Or you could write it recursively, with two base cases and a third accumulating parameter (by means of a helper function):
sumList :: Int -> [Int] -> Int
sumList n xs = sumList' n xs 0 where
sumList' :: Int -> [Int] -> Int -> Int
sumList' 0 _ a = _ -- A base case.
sumList' _ [] a = _ -- The other base case.
sumList' m (y:ys) a = sumList' _ _ _ -- The recursive case.
Here, the _ symbols on the left of the equals signs should stay there, and mean that the pattern guard ignores that parameter, but the _ symbols on the right are blanks for you to fill in yourself. Again, GHC will tell you the type you need to fill the holes with.
This kind of tail-recursive function is a very common pattern in Haskell; you want to make sure that each recursive call brings you one step closer to the base case. Often, that will mean calling itself with 1 subtracted from a count parameter, or calling itself with the tail of the list parameter as the new list parameter. here, you want to do both. Don't forget to update your running sum, a, when you have the function call itself recursively.
Here's a short-but-sweet answer. You're really close. Consider the following:
The take parameter tells you how many elements you need to sum up, so if you do sumList 0 anything you should always get 0 since you take no elements.
If you want the first n elements, you add the first element to your total and compute the sum of the next n-1 elements.
sumList 0 anything = 0
sumList n [] = 0
sumList n (e:es) = e + sumList (n-1) e
I have a bit of homework to do and I am a complete newbie to Haskell. The question I am having trouble with is to write a function which when given an integer x and a list of integers apply (x-y)*(x-y) to each element in the list and output the new list, with y being each element of the input list.
I have a very rough idea I will have to use the map function but I'm unsure how to go about it.
I have been looking at examples for squaring each element in a list and kind of understand how that works, but how I would implement the (x-y)*(x-y) with y being the current element completely baffles me.
squares :: [Int] -> [Int]
squares (x:xs) = x * x : squares xs
squares [] = []
the exact question I have been set is,
Write a function rela which takes as arguments an integer x and a list of integers. It returns a similar list, but where each element y has been replaced by (x-y)*(x-y), e.g.
Main> rela 2 [3,5,7]
[1,9,25]
I have managed to get it working after reading through some books, but the code I have made misses out the first element in the list. Any explanation why?
equation1 :: Int -> Int -> Int
equation1 x y = (x-y)*(x-y)
rela :: Int -> [Int] -> [Int]
rela x [] =[]
rela x (y:ys) = [ equation1 x y | y <- ys ]
First of all, you should probably create a separate function that does what you want.
e.g.
f x y = (x-y)*(x-y)
Now, every time you create a function in Haskell with multiple parameters, it actually "curries" the function, which means that you get a new function when you apply the first argument to it.
So, you would get a new function by doing this
g = f 5
The expression f 5 is actually a function
And you can apply a number to 'g' and x will always be '5'
So if we want to create a function that takes two parameters, 'x' and 'y', and applies (x-y)*(x-y) to a list where y is the current element, then all we need to do is the following:
f x y = (x-y)*(x-y)
squareDifference x = map (f x) [1,2,3,4]
Which you can use by calling squareDifference 5 or any other number as an argument
A more general version would allow you to pass in a list as well
squareDifference x xs = map (f x) xs
Which you would call by doing squareDifference 3 [1,2,3]
do you understand lambda functions?
map (\val -> the function) xs
is what you need.
currying is even better, but not as simple.
edit:
more conceptual...
map iterates down a list applying a function.
map (+ 3) xs
uses the currying technique mentioned above. you could also:
map (\x -> x + 3) xs
to accomplish the same thing.
Simple example:
rela :: Int -> [Int] -> [Int]
rela x = map (\y -> (x-y)*(x-y))
Or might you want any perversions? -) Here you are with Applicatives:
import Control.Applicative
rela :: Int -> [Int] -> [Int]
rela x = map $ (*) <$> (x-) <*> (x-)
Hello I guess you mean this:
Prelude> let rela n = map (\ x -> (x - n)^2)
Prelude> rela 2 [3,5,7]
[1,9,25]