Haskell - converting High Order Function to recursive function - haskell

requirement:write function single - Tests whether exactly one element of a list satisfies a given condition.
single :: (a -> Bool) -> [a] -> Bool
I wrote this function:
single p xs = count p xs == 1
where count pred = length . filter pred
Question: What is the easy (correct) way to convert the above functions into one recursive function without using " High Order Functions"?

You can do like that:
single p = lookupFirst
where
lookupFirst [] = False
lookupFirst (x:xs) | p x = lookupSecond xs
| otherwise = lookupFirst xs
lookupSecond [] = True
lookupSecond (x:xs) | p x = False
| otherwise = lookupSecond xs

We can use a none predicate that checks if the remainder of the list does not satisfy the condition:
single :: (a -> Bool) -> [a] -> Bool
single p [] = False
single p (x:xs) | p x = none p xs
| otherwise = single p xs
none :: (a -> Bool) -> [a] -> Bool
none _ [] = True
none p (x:xs) = not (p x) && none p xs
We thus also defined a none function that checks that no element in the given list satisfies a given predicate.
Or without passing the predicate through the recursion:
single :: (a -> Bool) -> [a] -> Bool
single p = helper
where helper [] = False
helper (x:xs) | p x = none xs
| otherwise = helper xs
none [] = True
none (x:xs) = not (p x) && none xs
The above written functions will also immediately stop from the moment a second item is found that satisfies the predicate. This can be useful if we work for instance with an infinite list. If there is a second item that satisfies the constraint, then the function will stop, if no such element or only one such element will ever be generated, we will however get stuck in an infinite loop (there is no much we can do about this). For example:
*Main> single even [1..] -- two or more elements satisfy the constraint
False
*Main> single even [1,3..] -- no element satisfies the constraint
^CInterrupted.
*Main> single even ([1,2]++[3,5..]) -- one element satisfies the constraint
^CInterrupted.

xor and foldl
The most intuitive thing I can thing of is to just fold xor (exclusive or) and your function f thru the list. In case you're not familiar with the binary function xor, it returns True only when (at most) 1 of its arguments are True; otherwise False
xor :: Bool -> Bool -> Bool
xor True b = not b
xor False b = b
single :: (a -> Bool) -> [a] -> Bool
single f [] = False
single f xs = foldl (\acc -> xor acc . f) False xs
main = do
putStrLn $ show (single even []) -- False
putStrLn $ show (single even [1]) -- False
putStrLn $ show (single even [2]) -- True
putStrLn $ show (single even [1,2]) -- True
putStrLn $ show (single even [1,2,3]) -- True
putStrLn $ show (single even [1,2,3,4]) -- False
Xor monoid
xor can be nicely encoded as a Monoid tho, which lends single to a more algebraic implementation using foldMap.
data Xor = Xor Bool
instance Monoid Xor where
mempty = Xor False
mappend (Xor True) (Xor b) = Xor (not b)
mappend (Xor False) (Xor b) = Xor b
single f xs = aux $ foldMap (Xor . f) xs
where
aux (Xor b) = b
main = do
putStrLn $ show (single even []) -- False
putStrLn $ show (single even [1]) -- False
putStrLn $ show (single even [2]) -- True
putStrLn $ show (single even [1,2]) -- True
putStrLn $ show (single even [1,2,3]) -- True
putStrLn $ show (single even [1,2,3,4]) -- False
auxiliary helper
This is another way you can do it with an auxiliary helper. This one has an added benefit in that it exits immediately (stops iteration thru the list) after an answer is determined
single :: (a -> Bool) -> [a] -> Bool
single f xs = aux False f xs
where
aux b f [] = b
aux True f (x:xs) = if (f x) then False else aux True f (xs)
aux False f (x:xs) = aux (f x) f xs
main = do
putStrLn $ show (single even []) -- False
putStrLn $ show (single even [1]) -- False
putStrLn $ show (single even [2]) -- True
putStrLn $ show (single even [1,2]) -- True
putStrLn $ show (single even [1,2,3]) -- True
putStrLn $ show (single even [1,2,3,4]) -- False
feedback welcome!
I'm a Haskell newbie but maybe these ideas are interesting to you. Or maybe they're bad! Leave me a comment if there's anything I can do to improve the answer ^_^

Related

Haskell map until first condition met

I want to map a conditional function only on the first item that passes.
map (>5) [1,2,3,4,5,6,7,8,9]
would result in
[False,False,False,False,False,True,True,True,True]
I'm looking for something that would result in
[False,False,False,False,False,True,False,False,False]
So only the first occurrence of being greater than 5 results in True.
I tried scanl, various folds and tried to roll my own mapUntil kind of thing.
Seems like a simple problem but I'm drawing a blank.
break specifically separates the list in 2 parts where the first part is all False, the opposite of span.
break (>5) [1,2,3,8,2,5,1,7,9]
>>> ([1,2,3],[8,2,5,1,7,9])
Then it's just what chi did:
oneTrue f lst = map (const False) a ++ rest b
where (a,b) = break f lst
rest [] = []
rest (x:xs) = True : map (const False) xs
A basic solution:
mapUntil p = onlyOne . map p
where
onlyOne [] = []
onlyOne (x:xs)
| x = True : map (const False) xs
| otherwise = False : onlyOne xs
With library helpers:
mapUntil p = snd . mapAccumL (\x y -> (x||y, not x && y)) False . map p
Above x is a boolean standing for "have seen a true before?", as a kind-of state. y is the list element. x||y is the new state, while not x && y is the new list element.
Alternatively (using Control.Arrow.second):
mapUntil p = uncurry (++) . second go . break id . map p
where
go [] = []
go (x:xs) = x : map (const False) xs
I would use the mapAccumL tool like;
λ> Data.List.mapAccumL (\b n -> if b then (b, (not b)) else (n > 5, n > 5)) False [1,2,3,4,5,6,7,8,9]
(True,[False,False,False,False,False,True,False,False,False])
Here we carry the b as the state of our interim calculations and in every step decide according to it's previous state. Obviously you need the snd part of the final result.
Edit : After reading the new comment of #Gord under his question I decided to extend my answer to cover his true problem.
Rephrasing the case event of branch that starts with pointerPress (x,y) into...
To start with, you never use x or y from the pattern match (x,y) so lets call it c. Then...
PointerPress c -> State circleCoords circleColors circleDraggeds c
where
bools = fmap checkMouseOverlaps $ (,) <$> circleCoords <*> [c]
circleDraggeds = snd $ mapAccumL (\a b -> if a then (a, not a)
else (b,b)) False bools
What's happening part;
(,) <$> circleCoords <*> [c]
circleCoords is a list of coordinates like [c0,c1,c2] and we fmap (the infix version (<$>) here) (,) function to it and it becomes an applicative of coordinates like [(c0,),(c1,),(c2,)]. Then we apply it to [c] aka [(x,y)] to turn it into [(c0,c),(c1,c),(c2,c)].
fmap checkMouseOverlaps $ toAbove
obviously yields to
[checkMouseOverlaps (c0,c), checkMouseOverlaps (c1,c), checkMouseOverlaps (c2,c)]
which is bools :: [Bool].
The the rest follows the logic explained at the top of my answer.
circleDraggeds = snd $ mapAccumL (\a b -> if a then (a, not a)
else (b,b)) False bools
This can be solve directly with recursion. Similar to chi's solution but without function composition
mapUntil :: (a -> Bool) -> [a] -> [Bool]
mapUntil _ [] = []
mapUntil f (x:xs) =
let b = f x -- calculate f x
in if b -- if true
then b : map (const False) xs -- prepend to the solution and map False to the rest of the list (b is True)
else b : mapUntil f xs -- keep applying mapUntil (b is False)
>>> mapUntil (>5) [1,2,3,4,5,6,7,8,9]
[False,False,False,False,False,True,False,False,False]
Map the condition over the list, then zip the result with the False prefix of the result concatenated with a True followed by an infinite list of Falses:
{-# LANGUAGE BlockArguments, ApplicativeDo, ViewPatterns #-}
import Control.Applicative (ZipList(..))
f :: (a -> Bool) -> [a] -> [Bool]
f cond (map cond -> bs) = getZipList do
r <- ZipList $ takeWhile not bs ++ [True] ++ repeat False
_ <- ZipList $ bs
pure r
or, equivalently:
f' :: (a -> Bool) -> [a] -> [Bool]
f' cond (map cond -> bs) = zipWith const (takeWhile not bs ++ [True] ++ repeat False) bs

Pattern Match on First and Last Items of List

Is it possible to pattern match on "starts with f", then any text, and "ends with b?
I tried:
f :: String -> Bool
f ('f':xs:'b') = True
f _ = False
But I got an error:
explore/PatternMatching.hs:2:11:
Couldn't match expected type ‘[Char]’ with actual type ‘Char’
In the pattern: 'b'
In the pattern: xs : 'b'
In the pattern: 'f' : xs : 'b'
Failed, modules loaded: none.
There is no easy way to do this without pattern matching language extensions. I would write it as:
f :: String -> Bool
f str = case (take 1 str, drop (length str - 1) str) of
("f", "b") -> True
otherwise -> False
(Using take and drop to avoid specially handling case of an empty string that might cause an error when using e.g. head or !!)
Prelude> f "flub"
True
Prelude> f "foo"
False
Prelude> f "fb"
True
Prelude> f "fbbbb"
True
Prelude> f "fbbbbf"
False
Prelude> f ""
False
As the previous answers state, there's no way to pattern-match directly for this. One might implement it as follows:
f 'f':xs#(_:_) = last xs == 'b' -- #(_:_) ensures nonempty tail
f _ = False
No, it is not possible directly.
: wants a list element on the left side, and a list on the right side.
'f':xs:'b' is invalid because there's something that is not a list on the right side of the second :.
'f':xs:"b" would be valid but won't do what you want, because xs is inferred to be a list element, not a list.
I would do this:
f s = f' (s, reverse s) where
f' ('f':_, 'b':_) = True
f' _ = False
Testing:
*Main> f ""
False
*Main> f "f"
False
*Main> f "b"
False
*Main> f "fb"
True
*Main> f "feeeeeeeb"
True
*Main> f (repeat 'b')
False
*Main> f (repeat 'f')
(hangs indefinitely)
For a list-like data-structure allowing you to access both its first and last element in constant time, you may want to have a look at Hinze and Paterson's fingertrees.
They are shipped by e.g. containers and here are the relevant views to deconstruct them. You may want to write your own view combining deconstruction on the left and the right if you are using this pattern a lot:
data ViewLR a = EmptyLR | SingleLR a | BothSides a (Seq a) a
viewlr :: Seq a -> ViewLR a
viewlr seq =
case viewl seq of
EmptyL -> EmptyLR
hd :< rest ->
case viewr rest of
EmptyR -> SingleLR hd
middle :> tl -> BothSides hd middle tl
You may also want to read up on View Patterns to be able to "pattern match" on the left rather than having to use case ... of.
Define a dedicated String data type and hence a form of pattern matching, for instance consider
data HString = Ends Char Char | Plain String
deriving (Show, Eq)
Thus
f :: HString -> Bool
f (Ends h l) = (h,l) == ('f','b')
f (Plain "") = False
f (Plain xs) = f $ Ends (head xs) (last xs)
and so
*Main> f (Plain "")
False
*Main> f (Plain "fabs")
False
*Main> f (Plain "fab")
True
Update
Similarly, consider the use of an infix operator :-: to denote a constructor, e.g
infixr 5 :-:
data HString = Char :-: Char | Plain String
deriving (Show, Eq)
and thus
f :: HString -> Bool
f (h :-: l) = (h,l) == ('f','b')
f (Plain "") = False
f (Plain xs) = f $ (head xs) :-: (last xs)
To understand the error simply check the signature of : operator
Prelude> :t (:)
(:) :: a -> [a] -> [a]
It can accept an element and a list to give the appended list. When you supply 'f':xs:'b', then it doesn't match the function call.

Checking to see if a list is ordered consecutively

Is there any library function in Haskell that'll allow me to check if a list is ordered consecutively? eg. [1,2,3,4] is valid, [1,2,3,10] is invalid.
Basically I can have a list that ranges anywhere between 3 to 5 elements and I'm trying to check if that list is ordered consecutively.
My Attempt (I'm not sure if this is the right way to approach it, seems to be way too much repetition)
isSucc:: [Integer] -> Bool
isSucc[] = True
isSucc(x:y:zs) =
if (x+1) == y
then True && isSucc(y:zs)
else isSucc(y:zs)
After I have this function working, I'm planning on using it to filter a lists of lists (Keep the list inside the list only and only if it is ordered consecutively)
You can use the trick zipWith f xs (drop 1 xs) to apply f to consecutive pairs of list elements. (Notice drop 1 rather than tail, because the latter fails if the list is empty!)
If you replace f with <= you'll get a list of Bool values. Now see whether they're all True.
isSucc xs = and $ zipWith (<=) xs (drop 1 xs)
There's no standard function for that.
Here's a fixed version of your function, making it generic, removing the redundant conditions and adding the missing ones:
isSucc :: (Enum a, Eq a) => [a] -> Bool
isSucc [] = True
isSucc (x:[]) = True
isSucc (x:y:zs) | y == succ x = isSucc $ y:zs
isSucc _ = False
I prefer to use a little more readable solution than one that has been offered by MathematicalOrchid.
First of all we will define the utilitarian function pairwise that might be useful in many different circumstances:
pairwise xs = zip xs $ tail xs
or in more modern way:
import Control.Applicative ((<*>))
pairwise = zip <*> tail
and then use it with the other combinators:
isSucc xs = all (\(x,y) -> succ x == y) $ pairwise xs
There is another way,
isOrdered :: (Enum a, Eq a) => (a -> a -> Bool) -> [a] -> Bool
isOrdered op (a:b:ls) = op a b && isOrdered op (b:ls)
isOrdered op _ = True
Thus,
isSucc = isOrdered ((==) . succ)
If you want to check that all consecutive differences are equal to one, you can use
isIncreasingByOne :: (Eq a, Num a) => [a] -> Bool
isIncreasingByOne = all (==1) (zipWith (-) (tail xs) xs)
This works for numeric types (hence the Num a constraint), including Float and Double. It's also easy to adapt if you want to check that a sequence is increasing by more than 5 at a time, say.
-- This checks if ordered
isordd:: [Int] -> Bool
isordd [] = True
isordd (x:y:xs)
| x > y = False
| lengh xs == 0 = True
| otherwise = isordd (y:xs)
-- This calculates the length of the list
lengh::[Int]->Int
lengh [] = 0
lengh (x:xs) = 1+lengh xs

How to implement a lazy constant-space tri-partition function?

I have generalized the existing Data.List.partition implementation
partition :: (a -> Bool) -> [a] -> ([a],[a])
partition p xs = foldr (select p) ([],[]) xs
where
-- select :: (a -> Bool) -> a -> ([a], [a]) -> ([a], [a])
select p x ~(ts,fs) | p x = (x:ts,fs)
| otherwise = (ts, x:fs)
to a "tri-partition" function
ordPartition :: (a -> Ordering) -> [a] -> ([a],[a],[a])
ordPartition cmp xs = foldr select ([],[],[]) xs
where
-- select :: a -> ([a], [a], [a]) -> ([a], [a], [a])
select x ~(lts,eqs,gts) = case cmp x of
LT -> (x:lts,eqs,gts)
EQ -> (lts,x:eqs,gts)
GT -> (lts,eqs,x:gts)
But now I'm facing a confusing behaviour when compiling with ghc -O1, the 'foo' and 'bar' functions work in constant-space, but the doo function leads to a space-leak.
foo xs = xs1
where
(xs1,_,_) = ordPartition (flip compare 0) xs
bar xs = xs2
where
(_,xs2,_) = ordPartition (flip compare 0) xs
-- pass-thru "least" non-empty partition
doo xs | null xs1 = if null xs2 then xs3 else xs2
| otherwise = xs1
where
(xs1,xs2,xs3) = ordPartition (flip compare 0) xs
main :: IO ()
main = do
print $ foo [0..100000000::Integer] -- results in []
print $ bar [0..100000000::Integer] -- results in [0]
print $ doo [0..100000000::Integer] -- results in [0] with space-leak
So my question now is,
What is the reason for the space-leak in doo, which seems suprising to me, since foo and bar don't exhibit such a space leak? and
Is there a way to implement ordPartition in such a way, that when used in the context of functions such as doo it performs with constant space complexity?
It's not a space leak. To find out whether a component list is empty, the entire input list has to be traversed and the other component lists constructed (as thunks) if it is. In the doo case, xs1 is empty, so the entire thing has to be built before deciding what to output.
That is a fundamental property of all partitioning algorithms, if one of the results is empty, and you check for its emptiness as a condition, that check cannot be completed before the entire list has been traversed.

Finding the first duplicate element in a list

I am very new to Haskell. I am trying to write code in Haskell that finds the first duplicate element from the list, and if it does not have the duplicate elements gives the message no duplicates. I know i can do it through nub function but i am trying to do it without it.
This is one way to do it:
import qualified Data.Set as Set
dup :: Ord a => [a] -> Maybe a
dup xs = dup' xs Set.empty
where dup' [] _ = Nothing
dup' (x:xs) s = if Set.member x s
then Just x
else dup' xs (Set.insert x s)
dupString :: (Ord a, Show a) => [a] -> [Char]
dupString x = case dup x of
Just x -> "First duplicate: " ++ (show x)
Nothing -> "No duplicates"
main :: IO ()
main = do
putStrLn $ dupString [1,2,3,4,5]
putStrLn $ dupString [1,2,1,2,3]
putStrLn $ dupString "HELLO WORLD"
Here is how it works:
*Main> main
No duplicates
First duplicate: 1
First duplicate: 'L'
This is not the your final answer, because it does unnecessary work when an element is duplicated multiple times instead of returning right away, but it illustrates how you might go about systematically running through all the possibilities (i.e. "does this element of the list have duplicates further down the list?")
dupwonub :: Eq a => [a] -> [a]
dupwonub [] = []
dupwonub (x:xs) = case [ y | y <- xs, y == x ] of
(y:ys) -> [y]
[] -> dupwonub xs
In case you are still looking into Haskell I thought you might like a faster, but more complicated, solution. This runs in O(n) (I think), but has a slightly harsher restriction on the type of your list, namely has to be of type Ix.
accumArray is an incredibly useful function, really recommend looking into it if you haven't already.
import Data.Array
data Occurances = None | First | Duplicated
deriving Eq
update :: Occurances -> a -> Occurances
update None _ = First
update First _ = Duplicated
update Duplicated _ = Duplicated
firstDup :: (Ix a) => [a] -> a
firstDup xs = fst . first ((== Duplicated).snd) $ (map g xs)
where dupChecker = accumArray update None (minimum xs,maximum xs) (zip xs (repeat ()))
g x = (x, dupChecker ! x)
first :: (a -> Bool) -> [a] -> a
first _ [] = error "No duplicates master"
first f (x:xs) = if f x
then x
else first f xs
Watch out tho, an array of size (minimum xs,maximum xs) could really blow up your space requirements.

Resources