Related
I have the following code, that drops every nth element in a list.
dropEvery :: [a] -> Int -> [a]
dropEvery xs n = f xs n ++ dropEvery (drop n xs) n
where
f ys 0 = []
f ys 1 = []
f [] m = []
f (y:ys) n = y : (f ys (n-1))
I would like to make it a bit shorter and was wondering if there is a way to use "<=" in pattern matching. I tried doing this using a where clause, which did not work, why?
f ys m = []
where
m <= 1 || ys == []
How can I shirk this redundancy? Is there a nice way to use "less or equal" in pattern matching?
EDIT: I tried this using guards
where
f ys m
| m <= 1 || null ys = []
| otherwise = (head ys) : (f (tail ys) (n-1))
You can work with a guard:
dropEvery :: [a] -> Int -> [a]
dropEvery xs n = f xs n ++ dropEvery (drop n xs) n
where
f ys i | i <= 1 = []
f [] _ = []
f (y:ys) n = y : (f ys (n-1))
If the condition in the guard is satisfied, then that clause "fires" and thus in this case will return an empty list [].
You will however get stuck in an infinite loop, since you write f xs n ++ dropEvery (n xs) n but drop 3 [] will return [], and thus it will keep calling dropEvery with an empty list.
You can make use of recursion where we each time decrement n until it reaches 0, and then we make two hops, so:
dropEvery :: Int -> [a] -> [a]
dropEvery n = go (n-1)
where go _ [] = []
go i (x:xs)
| i <= 0 = go (n-1) xs
| otherwise = x : go (i-1) xs
We can also work with splitAt :: [a] -> ([a], [a]) and with a pattern guard:
dropEvery n [] = []
dropEvery n ds
| (_:ys) <- sb = sa ++ dropEvery n ys
| otherwise = sa
where (sa, sb) = splitAt (n-1) ds
I'm trying to create a function definition for the function all using foldr. p is the predicate. I know this can be done:
all p = and . foldr (\x xs -> p x : xs) []
But what I want to do is to shift the function and into the foldr equation. Can this be done?
I've tried the following, which all failed to work:
all p = foldr (\x p -> \ys -> and (p x) ys) True
all p = foldr (\x and -> (\ys -> (p x and ys))) True
all p = foldr (\x ys -> and . (p x) ys) True
Am I falling short in my understanding of how to apply foldr?
We have
all p = and
. foldr (\x xs -> p x : xs) []
= foldr (&&) True -- {y : ys} -> y && {ys} 2-3
. foldr (\x xs -> p x : xs) [] -- {x , xs} -> p x : {xs} 1-2
= foldr (\x xs -> p x && xs) True -- {x , xs} -> p x && {xs} 1---3
because folding replaces each constructor with the specified combination operation (aka reducer), and replacing a cons of an element with a cons of a modified element, and then replacing that cons with (&&), is just replacing a cons of an element with the (&&) of a modified element right away:
a : ( b : ( c : ( d : ( ... )))) _OR_ [] -- | | 1
-- | |
p a : (p b : (p c : (p d : ( ... )))) _OR_ [] -- ↓ | | 2
-- | |
p a && (p b && (p c && (p d && ( ... )))) _OR_ True -- ↓ ↓ 3
In other words, folds compose by fusing their reducer functions, and reducer functions fuse by replacing the {constructors they use} with the next fold's reducer in the chain of folds, so that their corresponding transducers compose (as in Clojure's transducers); thus,
= foldr (reducingWith (&&)) True
. foldr ((mapping p) (:)) []
= foldr ((mapping p) (reducingWith (&&))) True
= foldr ((mapping p . reducingWith) (&&) ) True
-- first map p, then reduce with (&&)
for the appropriate definitions of reducingWith and mapping:
reducingWith cons x xs = cons x xs
mapping f cons x xs = cons (f x) xs
filtering p cons x xs | p x = cons x xs
| otherwise = xs
concatting t cons x xs = foldr cons xs (t x)
plz watch my code
insert x [] = [x]
insert x (y:ys)
| x < y = x:y:ys
| x == y = y:ys ++ [x]
| otherwise = y:insert x ys
insert_sort [] = []
insert_sort (x:xs) = insert x (insert_sort xs)
insert_pair (x,y) [] = [(x,y)]
insert_pair (x,y) ((a,b):yd)
| x > a = (a,b):insert_pair (x,y) yd
| otherwise = (x,y):(a,b):yd
insert_sort_pair [] = []
insert_sort_pair (x:xs) = insert_pair x (insert_sort_pair xs)
insert_high f [] = []
insert_high f (x:y:ys)
| f x y = x:y:ys
| otherwise = y:insert x ys
insert_high f ((a,b):(c,d):yd)
| f a c = (a,b):insert_pair (c,d) yd
| otherwise = (a,b):(c,d):yd
insert_sort_high f [] = []
insert_sort_high f (x:xs) = insert_high (f) x (insert_sort_high (f) xs)
I want to make insert_sort-high can do both insert_sort and insert_pair_sort.
"insert_sort_pair" compare the number in (number,symbol).
For example:
insert_sort_high (<) [3,5,2,1,4] -> [1,2,3,4,5]
insert_sort_high (>) [(2,'a'),(3,'b'),(1,'c')] -> [(1,'c'),(2,'a'),(3,'b')]
But, it doesn't work... how can i fix it?
First, a fundamental misunderstanding.
Write a type for insert_high - it should probably be (a -> a -> Bool) -> [a] -> [a]. But you've written a specialization for lists of tuples, so you've forced it to be less general than that.
You can only cover the general case. You're being misled by your examples.
I'd argue what you really want is
λ insert_sort_high (<) [3,5,2,1,4]
[1,2,3,4,5]
λ insert_sort_high (\(x,y) (a,b) -> x < a) [(2,'a'), (3,'b'), (1,'c')]
[(1,'c'),(2,'a'),(3,'b')]
The latter can be written a little more easily as
λ :m +Data.Function
λ insert_sort_high ((<) `on` fst) [(2,'a'), (3,'b'), (1,'c')]
[(1,'c'),(2,'a'),(3,'b')]
Of course, that's only if you only want sorting to be on the first element of the pair.
λ insert_sort_high ((<) `on` fst) [(2,'a'), (3,'b'), (1, 'a'), (1,'b'), (1,'c'), (1,'a')]
[(1,'a'),(1,'c'),(1,'b'),(1,'a'),(2,'a'),(3,'b')]
If you want to sort by the entire pair, you can do that too
λ (1,'a') < (1,'b')
True
λ (1,'z') < (2,'a')
True
λ insert_sort_high (<) [(2,'a'), (3,'b'), (1,'a'),(1,'b'),(1,'c'), (1,'a')]
[(1,'a'),(1,'a'),(1,'b'),(1,'c'),(2,'a'),(3,'b')]
But I digress.
With that in mind all you really need to do is delete your tuple case, and clean up some typos.
insert_high :: (a -> a -> Bool) -> a -> [a] -> [a]
insert_high _ x [] = [x]
insert_high f x (y:ys)
| f x y = x:y:ys
| otherwise = y : insert_high f x ys
insert_sort_high _ [] = []
insert_sort_high f (x:xs) = insert_high f x (insert_sort_high f xs)
So I am working on a function that detects if two binary trees have the same numbers in them.
So what I've come up with is the following which works just fine but the problem is that I am using total of 5 functions. Is there another way of detecting if two BT's have the same elements with just one function ? Here is my solution so far which seems to work just fine.
flatten :: BinTree a -> [a]
flatten Empty = []
flatten (Node l x r) = flatten l ++ [x] ++ flatten r
splt :: Int -> [a] -> ([a], [a])
splt 0 xs = ([], xs)
splt _ [] = ([],[])
splt n (x:xs) = (\ys-> (x:fst ys, snd ys)) (splt (n-1) xs)
merge :: Ord a => [a] -> [a] -> [a]
merge xs [] = xs
merge [] ys = ys
merge (x:xs) (y:ys) = if (x > y) then y:merge (x:xs) ys else x:merge xs(y:ys)
msort :: Ord a => [a] -> [a]
msort [] =[]
msort (x:[]) = (x:[])
msort xs = (\y -> merge (msort (fst y)) (msort (snd y))) (splt (length xs `div` 2) xs)
areTreesEqual :: (Ord a) => BinTree a -> BinTree a-> Bool
areTreesEqual Empty Empty = True
areTreesEqual Empty a = False
areTreesEqual a Empty = False
areTreesEqual a b = msort (flatten (a) ) == msort (flatten (b))
How about
import Data.MultiSet as Set
equal a b = accum a == accum b
where accum Empty = Set.empty
accum (Node l x r) = Set.insert x (accum l `Set.union` accum r)
Sets are lovely for unordered comparison and multisets will make sure that
1 /= 1
1 1
Eg, that duplicate numbers are counted properly. If this isn't a big concern, than swap MultiSet for Set. I think 3 lines is pretty decent for this sort of thing.
A couple of times I've found myself wanting a zip in Haskell that adds padding to the shorter list instead of truncating the longer one. This is easy enough to write. (Monoid works for me here, but you could also just pass in the elements that you want to use for padding.)
zipPad :: (Monoid a, Monoid b) => [a] -> [b] -> [(a, b)]
zipPad xs [] = zip xs (repeat mempty)
zipPad [] ys = zip (repeat mempty) ys
zipPad (x:xs) (y:ys) = (x, y) : zipPad xs ys
This approach gets ugly when trying to define zipPad3. I typed up the following and then realized that of course it doesn't work:
zipPad3 :: (Monoid a, Monoid b, Monoid c) => [a] -> [b] -> [c] -> [(a, b, c)]
zipPad3 xs [] [] = zip3 xs (repeat mempty) (repeat mempty)
zipPad3 [] ys [] = zip3 (repeat mempty) ys (repeat mempty)
zipPad3 [] [] zs = zip3 (repeat mempty) (repeat mempty) zs
zipPad3 xs ys [] = zip3 xs ys (repeat mempty)
zipPad3 xs [] zs = zip3 xs (repeat mempty) zs
zipPad3 [] ys zs = zip3 (repeat mempty) ys zs
zipPad3 (x:xs) (y:ys) (z:zs) = (x, y, z) : zipPad3 xs ys zs
At this point I cheated and just used length to pick the longest list and pad the others.
Am I overlooking a more elegant way to do this, or is something like zipPad3 already defined somewhere?
How about custom head and tail functions (named next and rest in my example below)?
import Data.Monoid
zipPad :: (Monoid a, Monoid b) => [a] -> [b] -> [(a,b)]
zipPad [] [] = []
zipPad xs ys = (next xs, next ys) : zipPad (rest xs) (rest ys)
zipPad3 :: (Monoid a, Monoid b, Monoid c) => [a] -> [b] -> [c] -> [(a,b,c)]
zipPad3 [] [] [] = []
zipPad3 xs ys zs = (next xs, next ys, next zs) : zipPad3 (rest xs) (rest ys) (rest zs)
next :: (Monoid a) => [a] -> a
next [] = mempty
next xs = head xs
rest :: (Monoid a) => [a] -> [a]
rest [] = []
rest xs = tail xs
Test snippet:
instance Monoid Int where
mempty = 0
mappend = (+)
main = do
print $ zipPad [1,2,3,4 :: Int] [1,2 :: Int]
print $ zipPad3 [1,2,3,4 :: Int] [9 :: Int] [1,2 :: Int]
Its output:
[(1,1),(2,2),(3,0),(4,0)]
[(1,9,1),(2,0,2),(3,0,0),(4,0,0)]
This pattern comes up quite a lot. A solution I learned from Paul Chiusano is as follows:
data These a b = This a | That b | These a b
class Align f where
align :: (These a b -> c) -> f a -> f b -> f c
instance Align [] where
align f [] [] = []
align f (x:xs) [] = f (This x) : align f xs []
align f [] (y:ys) = f (That y) : align f [] ys
align f (x:xs) (y:ys) = f (These x y) : align f xs ys
liftAlign2 f a b = align t
where t (This l) = f l b
t (That r) = f a r
t (These l r) = f l r
zipPad a b = liftAlign2 (,) a b
liftAlign3 f a b c xs ys = align t (zipPad a b xs ys)
where t (This (x,y)) = f x y c
t (That r) = f a b r
t (These (x,y) r) = f x y r
zipPad3 a b c = liftAlign3 (,,) a b c
A little test in ghci:
*Main> zipPad3 ["foo", "bar", "baz"] [2, 4, 6, 8] [True, False] "" 0 False
[("foo",2,True),("bar",4,False),("baz",6,False),("",8,False)]
A simpler way to do this is with Maybe. I will illustrate with Edward's
more general formulation:
import Data.Maybe
import Control.Applicative
zipWithTails l r f as bs = catMaybes . takeWhile isJust $
zipWith fMaybe (extend as) (extend bs)
where
extend xs = map Just xs ++ repeat Nothing
fMaybe a b = liftA2 f a b <|> fmap l a <|> fmap r b
There are times when you want to be able to apply a different function to either tail rather than just supply mempty or manual zeroes as well:
zipWithTail :: (a -> a -> a) -> [a] -> [a] -> [a]
zipWithTail f (a:as) (b:bs) = f a b : zipWithTails f as bs
zipWithTail f [] bs = bs
zipWithTail f as _ = as
zipWithTails :: (a -> c) -> (b -> c) -> (a -> b -> c) -> [a] -> [b] -> [c]
zipWithTails l r f (a:as) (b:bs) = f a b : zipWithTails l r f as bs
zipWithTails _ r _ [] bs = fmap r bs
zipWithTails l _ _ as _ = fmap l as
I use the former when I'm doing something like zipWithTail (+)
and the former when I need to do something like zipWithTail (*b) (a*) (\da db -> a*db+b*da) since the former can be much more efficient than feeding a default into a function, and the latter a little bit so.
However, if you just wanted to make a more succinct version of what you have, you could probably turn to mapAccumL ,but its not any clearer, and the ++ can be expensive.
zipPad as bs = done $ mapAccumL go as bs
where go (a:as) b = (as,(a,b))
go [] b = ([],(mempty,b))
done (cs, both) = both ++ fmap (\x -> (x, mempty)) cs