How I can set the signature of a function right? - haskell

I'm practicing some Haskell to understand the \, case.. of and Maybe better.
I've got this little function here which should return Nothing if the array is empty, Just y if y is equal to the head of the array xs and Just (tail xs) if y is not equal to the head of the array xs.
I set the return type of the function to Maybe a because in one case it should return an Int and in the other an [Int].
funct :: Int -> [Int] -> Maybe a
funct = \y xs -> case xs of
[] -> Nothing
xs -> if ((head xs) == y)
then Just y
else Just (tail xs)
What am I missing? I am getting the error that it couldn't match type a with [Int]. Isn't the a in Maybe a generic or is it influenced by the fact that I "used" the a as an Int in the Just y part?
EDIT: Ok my suggestion was bs, I tested it with Just (tail xs) in the then and else part and I'm still getting the same error.

set the return type of the function to Maybe a because in one case it should return an Int and in the other an [Int].
Haskell is statically typed. Meaning it can not - at runtime - have a different return type. It can only have one return type. a is not an ad hoc type (in the sense that it can be any type at runtime). It means that a will be determined - at compile time - based on the types of other parameters.
For instance you can write: foo :: a -> a -> a to specify that if foo takes two Ints (again known at compile time), the result will be an Int.
You can however use Either a b to say that you will either return a Left a, or a Right b. So you can rewrite it to:
funct :: Int -> [Int] -> Maybe (Either Int [Int])
funct = \y xs -> case xs of
[] -> Nothing
xs -> if ((head xs) == y)
then Just (Left y)
else Just (Right (tail xs))
Your function however is quite verbose, you can make it more clear and compact as follows:
funct :: Int -> [Int] -> Maybe (Either Int [Int])
funct _ [] = Nothing
funct y (h:t) | h == y = Just (Left y)
| otherwise = Just (Right t)
Furthermore we can generalize it to:
funct :: Eq a => a -> [a] -> Maybe (Either a [a])
funct _ [] = Nothing
funct y (h:t) | h == y = Just (Left y)
| otherwise = Just (Right t)
Here Eq is a typeclass that specifies that there exists a function (==) :: a -> a -> Bool that we can use. Otherwise using == in the body of the function would not be possible.
Furthermore we use patterns in the head of every clause. [] is a pattern that describes the empty list. (h:t) on the other hand is a pattern describing a list containing at least one element: the head h, followed by a (possibly empty tail t).

Related

Trying to code my own 'partition' function in haskell

as the title says, I'm trying to recode this function but I keep getting an error that says that the type that I output doesnt match the expected type. Could someone help me with this? Here's my code :
myPartition :: (a -> Bool) -> [a] -> ([a], [a])
myPartition f (x:xs) = if f x
then (x : myPartition f xs, [])
else ([], x : myPartition f xs)
myPartition _ [] = ([], [])
Also, im not authorized to use any function of the standard library
The main problem is that your function checks if f x holds, and if so constructs a 2-tuple where it will write the entire result of the recursive call. That result will be a 2-tuple as well, so you try to use a 2-tuple as an element in a 2-tuple as an element in a …
You should make a recursive call to obtain a 2-tuple of elements for the rest of the list, and the prepend the item to any of the two, so:
myPartition :: (a -> Bool) -> [a] -> ([a], [a])
myPartition p = go
where go (x:xs)
| p x = (…, …)
| otherwise = (…, …)
where (pa, pb) = go xs
go [] = ([], [])
where you still need to fill in the … parts.

Haskell: for every even appearance in an array, concatenate an int to the final list

I'm currently trying to write a function that takes as arguments an Int and an array of Ints and for every even value in the array, it concatenates the Int to the final array.
So, something like this:
f 3 [1,2,3,4,5,6] = [1,2,3,3,4,3,5,6,3]
This is the code I imagined would work (I'm just beginning so sorry if it's bad):
f :: Int -> [Int] -> [Int]
f(x,[]) = []
f(x,y)
|even head(y) = (head(y) ++ [x] ++ f(x,drop 1 y)
|otherwise = head(y) ++ f(x,(drop 1 y))
The error I'm getting is "Couldn't match expected type of 'Int' with actual type (a3, [[a3]])'. I understand the parameters types are mismatched, but I'm not sure how a proper syntax would look like here
You use (x, []), so that means the input type would be a tuple, so f :: (Int, [Int]) -> [Int].
I would also use pattern matching instead of head and tail, so:
f :: Int -> [Int] -> [Int]
f _ [] = []
f x (y:ys)
| even y = y : x : f x ys
| otherwise = y : f x ys
You can also generalize the type signature, and work with an inner function to avoid passing the x each time:
f :: Integral a => a -> [a] -> [a]
f x = go
where go [] = []
go (y:ys)
| even y = y : x : go ys
| otherwise = y : go ys
Another way of looking at this would be using a right fold to insert the desired element after even numbers.
f :: Int -> [Int] -> [Int]
f x lst = foldr (\y i -> if even y then y:x:i else y:i) [] lst
Which we can simplify to:
f :: Int -> [Int] -> [Int]
f x = foldr (\y i -> if even y then y:x:i else y:i) []
Note that without specifying the type, the more general inferred type of f would be:
f :: (Foldable t, Integral a) => a -> t a -> [a]

Is there a straight-forward solution to receiving the element *prior* to hitting the dropWhile predicate?

Given a condition, I want to search through a list of elements and return the first element that reaches the condition, and the previous one.
In C/C++ this is easy :
int i = 0;
for(;;i++) if (arr[i] == 0) break;
After we get the index where the condition is met, getting the previous element is easy, through "arr[i-1]"
In Haskell:
dropWhile (/=0) list gives us the last element I want
takeWhile (/=0) list gives us the first element I want
But I don't see a way of getting both in a simple manner. I could enumerate the list and use indexing, but that seems messy. Is there a proper way of doing this, or a way of working around this?
I would zip the list with its tail so that you have pairs of elements
available. Then you can just use find on the list of pairs:
f :: [Int] -> Maybe (Int, Int)
f xs = find ((>3) . snd) (zip xs (tail xs))
> f [1..10]
Just (3,4)
If the first element matches the predicate this will return
Nothing (or the second match if there is one) so you might need to special-case that if you want something
different.
As Robin Zigmond says break can also work:
g :: [Int] -> (Int, Int)
g xs = case break (>3) xs of (_, []) -> error "not found"
([], _) -> error "first element"
(ys, z:_) -> (last ys, z)
(Or have this return a Maybe as well, depending on what you need.)
But this will, I think, keep the whole prefix ys in memory until it
finds the match, whereas f can start garbage-collecting the elements
it has moved past. For small lists it doesn't matter.
I would use a zipper-like search:
type ZipperList a = ([a], [a])
toZipperList :: [a] -> ZipperList a
toZipperList = (,) []
moveUntil' :: (a -> Bool) -> ZipperList a -> ZipperList a
moveUntil' _ (xs, []) = (xs, [])
moveUntil' f (xs, (y:ys))
| f y = (xs, (y:ys))
| otherwise = moveUntil' f (y:xs, ys)
moveUntil :: (a -> Bool) -> [a] -> ZipperList a
moveUntil f = moveUntil' f . toZipperList
example :: [Int]
example = [2,3,5,7,11,13,17,19]
result :: ZipperList Int
result = moveUntil (>10) example -- ([7,5,3,2], [11,13,17,19])
The good thing about zippers is that they are efficient, you can access as many elements near the index you want, and you can move the focus of the zipper forwards and backwards. Learn more about zippers here:
http://learnyouahaskell.com/zippers
Note that my moveUntil function is like break from the Prelude but the initial part of the list is reversed. Hence you can simply get the head of both lists.
A non-awkward way of implementing this as a fold is making it a paramorphism. For general explanatory notes, see this answer by dfeuer (I took foldrWithTails from it):
-- The extra [a] argument f takes with respect to foldr
-- is the tail of the list at each step of the fold.
foldrWithTails :: (a -> [a] -> b -> b) -> b -> [a] -> b
foldrWithTails f n = go
where
go (a : as) = f a as (go as)
go [] = n
boundary :: (a -> Bool) -> [a] -> Maybe (a, a)
boundary p = foldrWithTails findBoundary Nothing
where
findBoundary x (y : _) bnd
| p y = Just (x, y)
| otherwise = bnd
findBoundary _ [] _ = Nothing
Notes:
If p y is true we don't have to look at bnd to get the result. That makes the solution adequately lazy. You can check that by trying out boundary (> 1000000) [0..] in GHCi.
This solution gives no special treatment to the edge case of the first element of the list matching the condition. For instance:
GHCi> boundary (<1) [0..9]
Nothing
GHCi> boundary even [0..9]
Just (1,2)
There's several alternatives; either way, you'll have to implement this yourself. You could use explicit recursion:
getLastAndFirst :: (a -> Bool) -> [a] -> Maybe (a, a)
getLastAndFirst p (x : xs#(y:ys))
| p y = Just (x, y)
| otherwise = getLastAndFirst p xs
getLastAndFirst _ [] = Nothing
Alternately, you could use a fold, but that would look fairly similar to the above, except less readable.
A third option is to use break, as suggested in the comments:
getLastAndFirst' :: (a -> Bool) -> [a] -> Maybe (a,a)
getLastAndFirst' p l =
case break p l of
(xs#(_:_), (y:_)) -> Just (last xs, y)
_ -> Nothing
(\(xs, ys) -> [last xs, head ys]) $ break (==0) list
Using break as Robin Zigmond suggested ended up short and simple, not using Maybe to catch edge-cases, but I could replace the lambda with a simple function that used Maybe.
I toyed a bit more with the solution and came up with
breakAround :: Int -> Int -> (a -> Bool) -> [a] -> [a]
breakAround m n cond list = (\(xs, ys) -> (reverse (reverse take m (reverse xs))) ++ take n ys) $ break (cond) list
which takes two integers, a predicate, and a list of a, and returns a single list of m elements before the predicate and n elements after.
Example: breakAround 3 2 (==0) [3,2,1,0,10,20,30] would return [3,2,1,0,10]

Haskell filter function with multiple parameters

I'm trying to learn Haskell and wondered how to filter a given list, with a function that takes multiple parameters, passing each element of the list with other unchanging elements to the function, to create a new list.
I understand that I can do this to use a bool function to filter the list:
newList = filter theFunction aList
but what happens when the theFunction takes other parameters like this:
theFunction -> elementOfAList -> Int -> Bool
how then could I filter each element of the list, whilst parsing in another element to the function? Any help would be greatly appreciated :)
Edit -> To provide some more information, if I wanted to have a list of integers from [1..10], that get filtered through a function that takes two integers and returns true if the first one is smaller, how could I do that?
In that case you use a partially applied predicate function, like this
-- theFunction :: elementOfAList -> Int -> Bool -- "::" means, "is of type"
newList = filter (flip theFunction i) aList
because
flip theFunction i x = theFunction x i
by the definition of flip, so flip theFunction has the type Int -> elementOfAList -> Bool:
flip :: (a -> b -> c ) -> b -> a -> c
theFunction :: a -> Int -> Bool
flip theFunction :: Int -> a -> Bool
flip theFunction (i :: Int) :: a -> Bool
where i is some Int value defined elsewhere. a is a type variable, i.e. it can be any type, like the type of a list's elements (i.e. for a list aList :: [a] each element has the same type, a).
For example, with theFunction x i = x < i you could call filter (flip theFunction 5) aList, keeping in the resulting list all the elements of aList that are smaller than 5. Normally this would just be written as filter (< 5) aList, with operator sections (of which (< 5) is one example, absolutely equivalent to the flip theFunction 5).
The above filtering will use the same Int value i in calling theFunction for every element x of a list aList. If you wanted to recalculate that Int, it is done with another pattern (i.e., higher-order function),
mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
Suppose you wanted to keep in a list of ints all the elements as they are being found by theFunction. Then you could do it like
theFunction :: elementOfAList -> Int -> Bool
foo :: Int -> [Int] -> [Int]
foo i xs = concat (snd (mapAccumL g i xs)) -- normally written as
-- concat $ snd $ mapAccumL g i xs -- or
-- concat . snd $ mapAccumL g i xs -- or even
-- concat . snd . mapAccumL g i $ xs
where
g acc x -- g :: (acc -> x -> (acc, y)) according to mapAccumL's signature
| theFunction x acc = (x, [x]) -- include `x` in output, and update the acc
| otherwise = (acc, []) -- keep the accumulated value, and skip this `x`
Because both x and acc are used in the same role (the first element of the tuple) they both must be of same type.

Converting a foldl into fold1

I am using the following fold to get the final monotonically decreasing sequence of a list.
foldl (\acc x -> if x<=(last acc) then acc ++ [x] else [x]) [(-1)] a
So [9,5,3,6,2,1] would return [6,2,1]
However, with foldl I needed to supply a start for the fold namely [(-1)]. I was trying to turn into to a foldl1 to be able to handle any range of integers as well as any Ord a like so:
foldl1 (\acc x -> if x<=(last acc) then acc ++ [x] else [x]) a
But I get there error:
cannot construct infinite type: a ~ [a]
in the second argument of (<=) namely last acc
I was under the impression that foldl1 was basically :
foldl (function) [head a] a
But I guess this isn't so? How would you go about making this fold generic for any Ord type?
I was under the impression that foldl1 was basically :
foldl (function) [head a] a
No, foldl1 is basically:
foldl function (head a) (tail a)
So the initial element is not a list of head a, but head a.
How would you go about making this fold generic for any Ord type?
Well a quick fix is:
foldl (\acc x -> if x<=(last acc) then acc ++ [x] else [x]) [head a] (tail a)
But there are still two problems:
in case a is an empty list, this function will error (while you probably want to return the empty list); and
the code is not terribly efficient since both last and (++) run in O(n).
The first problem can easily be addressed by using pattern matching to prevent that scenario. But for the latter you better would for instance use a reverse approach. Like for instance:
f :: Ord t => [t] -> [t]
f [] = [] -- case when the empty list is given
f a = reverse $ foldl (\acc#(ac:_) x -> if x <= ac then (x:acc) else [x]) [head a] (tail a)
Furthermore personally I am not a huge fan of if-then-else in functional programming, you can for instance define a helper function like:
f :: Ord t => [t] -> [t]
f [] = [] -- case when the empty list is given
f a = reverse $ foldl g [head a] (tail a)
where g acc#(ac:_) x | x <= ac = (x:acc)
| otherwise = [x]
Now reverse runs in O(n) but this is done only once. Furthermore the (:) construction runs in O(1) so all the actions in g run in O(1) (well given the comparison of course works efficient, etc.) making the algorithm itself O(n).
For your sample input it gives:
*Main> f [9,5,3,6,2,1]
[6,2,1]
The type of foldl1 is:
Foldable t => (a -> a -> a) -> t a -> a
Your function argument,
\acc x -> if x<=(last acc) then acc ++ [x] else [x]
has type:
(Ord a) => [a] -> a -> [a]
When Haskell's typechecker tries typechecking your function, it'll try unifying the type a -> a -> a (the type of the first argument of foldl1) with the type [a] -> a -> [a] (the type of your function).
To unify these types would require unifying a with [a], which would lead to the infinite type a ~ [a] ~ [[a]] ~ [[[a]]]... and so on.
The reason this works while using foldl is that the type of foldl is:
Foldable t => (b -> a -> b) -> b -> t a -> b
So [a] gets unified with b and a gets unified with the other a, leading to no problem at all.
foldl1 is limited in that it can only take functions which deal with only one type, or, in other terms, the accumulator needs to be the same type as the input list (for instance, when folding a list of Ints, foldl1 can only return an Int, while foldl can use arbitrary accumulators. So you can't do this using foldl1).
With regards to making this generic for all Ord values, one possible solution is to make a new typeclass for values which state their own "least-bound" value, which would then be used by your function. You can't make this function as it is generic on all Ord values because not all Ord values have sequence least bounds you can use.
class LowerBounded a where
lowerBound :: a
instance LowerBounded Int where
lowerBound = -1
finalDecreasingSequence :: (Ord a, LowerBounded a) => [a] -> [a]
finalDecreasingSequence = foldl buildSequence lowerBound
where buildSequence acc x
| x <= (last acc) = acc ++ [x]
| otherwise = [x]
You might also want to read a bit about how Haskell does its type inference, as it helps a lot in figuring out errors like the one you got.

Resources