Related
How can I get a maximum element of an effectful container where computing attribute to compare against also triggers an effect?
There has to be more readable way of doing things like:
latest dir = Turtle.fold (z (ls dir)) Fold.maximum
z :: MonadIO m => m Turtle.FilePath -> m (UTCTime, Turtle.FilePath)
z mx = do
x <- mx
d <- datefile x
return (d, x)
I used overloaded version rather than non-overloaded maximumBy but the latter seems better suite for ad-hoc attribute selection.
How can I be more methodic in solving similar problems?
So I know nothing about Turtle; no idea whether this fits well with the rest of the Turtle ecosystem. But since you convinced me in the comments that maximumByM is worth writing by hand, here's how I would do it:
maximumOnM :: (Monad m, Ord b) => (a -> m b) -> [a] -> m a
maximumOnM cmp [x] = return x -- skip the effects if there's no need for comparison
maximumOnM cmp (x:xs) = cmp x >>= \b -> go x b xs where
go x b [] = return x
go x b (x':xs) = do
b' <- cmp x'
if b < b' then go x' b' xs else go x b xs
I generally prefer the *On versions of things -- which take a function that maps to an Orderable element -- to the *By versions -- which take a function that does the comparison directly. A maximumByM would be similar but have a type like Monad m => (a -> a -> m Ordering) -> [a] -> m a, but this would likely force you to redo effects for each a, and I'm guessing it's not what you want. I find *On more often matches with the thing I want to do and the performance characteristics I want.
Since you're already familiar with Fold, you might want to get to know FoldM, which is similar.
data FoldM m a b =
-- FoldM step initial extract
forall x . FoldM (x -> a -> m x) (m x) (x -> m b)
You can write:
maximumOnM ::
(Ord b, Monad m)
=> (a -> m b) -> FoldM m a (Maybe a)
maximumOnM f = FoldM combine (pure Nothing) (fmap snd)
where
combine Nothing a = do
f_a <- f a
pure (Just (f_a, a))
combine o#(Just (f_old, old)) new = do
f_new <- f new
if f_new > f_old
then pure $ Just (f_new, new)
else pure o
Now you can use Foldl.foldM to run the fold on a list (or other Foldable container). Like Fold, FoldM has an Applicative instance, so you can combine multiple effectful folds into one that interleaves the effects of each of them and combines their results.
It's possible to run effects on foldables using reducers package.
I'm not sure if it's correct, but it leverages existing combinators and instances (except for Bounded (Maybe a)).
import Data.Semigroup.Applicative (Ap(..))
import Data.Semigroup.Reducer (foldReduce)
import Data.Semigroup (Max(..))
import System.IO (withFile, hFileSize, IOMode(..))
-- | maxLength
--
-- >>> getMax $ maxLength ["abc","a","hello",""]
-- 5
maxLength :: [String] -> (Max Int)
maxLength = foldReduce . map (length)
-- | maxLengthIO
--
-- Note, this runs IO...
--
-- >>> (getAp $ maxLengthIO ["package.yaml", "src/Lib.hs"]) >>= return . getMax
-- Just 1212
--
-- >>> (getAp $ maxLengthIO []) >>= return . getMax
-- Nothing
maxLengthIO :: [String] -> Ap IO (Max (Maybe Integer))
maxLengthIO xs = foldReduce (map (fmap Just . f) xs) where
f :: String -> IO Integer
f s = withFile s ReadMode hFileSize
instance Ord a => Bounded (Maybe a) where
maxBound = Nothing
minBound = Nothing
I understand that it's impossible to pattern match functions in Haskell, and I fully understand why. However, I have two closely related questions. First, in cases where you'd like to partially apply functions for use later, is there a way of defining and capturing the return if it's a tuple? Or am I wrong, and this is still trying to pattern match functions under my nose?
For example, suppose I'm trying to get the quotient and remainder of a value with various multiples of ten. Then, how would I write something like this?
q, r :: Integral a => a -> a
(q, r) = (12345 `quotRem`)
I realize here, there are separate functions that exist, so I could do this instead:
q, r :: Integral a => a -> a
q = (12345 `quot`)
r = (12345 `rem`)
However, that's a very specific case, and there are unlimited other examples of functions that return tuples that would be nice to generalize. For example, a function that returns the number of evens and odds in a list.
evens, odds :: Integral a => [a] -> Int
(evens, odds) = (length . (filter even), length . (filter odd))
This leads me to my second question. The above works just fine in GHCi.
Prelude> let (evens, odds) = (length . (filter even), length . (filter odd))
Prelude> :t evens
evens :: Integral a => [a] -> Int
Prelude> evens [1..10]
5
What's even more confusing is it even works by "pattern-matching" in the same way that I was playing with (q, r) in the beginning:
Prelude> let evensOdds = (length . (filter even), length . (filter odd))
Prelude> :t evensOdds
evensOdds :: (Integral a1, Integral a) => ([a1] -> Int, [a] -> Int)
Prelude> let (ev,od) = evensOdds
Prelude> :t ev
ev :: Integral a1 => [a1] -> Int
Prelude> ev [1..10]
5
It also works just fine in an actual file loaded into GHCi, even though (evens, odds) doesn't. Why are these two different, and why does the second one work in GHCi at all if it doesn't work normally? Can what's different here be leveraged in some way?
You never pattern matched on a function. You always pattern matched on the pair-constructor (,). Your (even, odds) example
(evens, odds) = (length . (filter even), length . (filter odd))
just works like
(first, second) = (x, y)
It doesn't matter what type x and y have at that point.
Your (q, r) example doesn't work due to quotRem's type. Let's recall it and compare it with (q, r)'s type:
quotRem :: Integral n => n -> n -> (n , n)
quotRem 12345 :: Integral n => n -> (n , n)
(q, r) :: Integral n => (n -> n, n -> n)
As you can see, the pair (q, r)'type differs from quotRem's one. Still, it's possible to write your function:
pairify :: (a -> (b, c)) -> (a -> b, a -> c)
pairify f = (fst . f, snd . f)
(q,r) = pairify (quotRem 12345)
But as you can see we don't gain too much from pairify. By the way, partition from Data.List provides your (even, odds) functionality:
(even, odds) = pairify (partition even)
Look at the type of (12345 `quotRem`):
Integral a => a -> (a, a)
It’s a single function that returns a tuple. If you want to make this into a tuple of functions, you can compose it with fst and snd:
(q, r) = (fst . f, snd . f)
where f = (12345 `quotRem`)
If you want to do this in a point-free way, one way is to use the &&& combinator from Control.Arrow. Its fully general type is:
Arrow a => a b c -> a b d -> a b (c, d)
Specialised to the -> arrow, that’s:
(b -> c) -> (b -> d) -> b -> (c, d)
So it takes two functions, each taking a value of type b, and returns both their results (of types c and d) in a tuple. So here you can do something like this:
split = (fst .) &&& (snd .)
(q, r) = split (12345 `quotRem`)
Whereas if you look at the type of (length . filter even, length . filter odd), it’s a tuple already,
(Integral a, Integral b) => ([a] -> Int, [b] -> Int)
Which is why of course you can destructure this tuple to bind evens and odds.
I have a task in Haskell (no, it's not my homework, I'm learning for exam).
The task is:
Write point-free function numocc which counts occurrences of element in given lists. For example: numocc 1 [[1, 2], [2, 3, 2, 1, 1], [3]] = [1, 2, 0]
This is my code:
addif :: Eq a => a -> Int -> a -> Int
addif x acc y = if x == y then acc+1 else acc
count :: Eq a => a -> [a] -> Int
count = flip foldl 0 . addif
numocc :: Eq a => a -> [[a]] -> [Int]
numocc = map . count
numocc and count are 'point-free', but they are using function addif which isn't.
I have no idea how can I do the function addif point-free. Is there any way to do if statement point-free? Maybe there is a trick which use no if?
I would use the fact that you can easily convert a Bool to an Int using fromEnum:
addif x acc y = acc + fromEnum (x == y)
Now you can start applying the usual tricks to make it point-free
-- Go prefix and use $
addif x acc y = (+) acc $ fromEnum $ (==) x y
-- Swap $ for . when dropping the last argument
addif x acc = (+) acc . fromEnum . (==) x
And so on. I won't take away all the fun of making it point free, especially when there's tools to do it for you.
Alternatively, you could write a function like
count x = sum . map (fromEnum . (==) x)
Which is almost point free, and there are tricks that get you closer, although they get pretty nasty quickly:
count = fmap fmap fmap sum map . fmap fmap fmap fromEnum (==)
Here I think it actually looks nicer to use fmap instead of (.), although you could replace every fmap with (.) and it would be the exact same code. Essentially, the (fmap fmap fmap) composes a single argument and a two argument function together, if you instead give it the name .: you could write this as
count = (sum .: map) . (fromEnum .: (==))
Broken down:
> :t fmap fmap fmap sum map
Num a => (a -> b) -> [a] -> b
So it takes a function from b to a numeric a, a list of bs, and returns an a, not too bad.
> :t fmap fmap fmap fromEnum (==)
Eq a => a -> a -> Int
And this type can be written as Eq a => a -> (a -> Int), which is an important thing to note. That makes this function's return type match the input to fmap fmap fmap sum map with b ~ Int, so we can compose them to get a function of type Eq a => a -> [a] -> Int.
why not
numocc x
= map (length . filter (== x))
= map ((length .) (filter (== x)) )
= map (((length .) . filter) (== x))
= map (((length .) . filter) ((==) x))
= map (((length .) . filter . (==)) x)
= (map . ((length .) . filter . (==))) x
= (map . (length .) . filter . (==)) x
and then the trivial eta-contraction.
One trick would be to import one of the many if functions, e.g. Data.Bool.bool 1 0 (also found in Data.Bool.Extras).
A more arcane trick would be to use Foreign.Marshal.Utils.fromBool, which does exactly what you need here. Or the same thing, less arcane: fromEnum (thanks #bheklilr).
But I think the simplest trick would be to simply avoid counting yourself, and just apply the standard length function after filtering for the number.
Using the Enum instance for Bool, it is possible to build a pointfree replacement for if that can be used in more general cases:
chk :: Bool -> (a,a) -> a
chk = ([snd,fst]!!) . fromEnum
Using chk we can define a different version of addIf:
addIf' :: Eq a => a -> a -> Int -> Int
addIf' = curry (flip chk ((+1),id) . uncurry (==))
Now we can simply replace chk in addIf':
addIf :: Eq a => a -> a -> Int -> Int
addIf = curry (flip (([snd,fst]!!) . fromEnum) ((+1),id) . uncurry (==))
I think you’re looking for Data.Bool’s bool, which exists since 4.7.0.0 (2014–04–08).
incif :: (Eq a, Enum counter) => a -> a -> counter -> counter
incif = ((bool id succ) .) . (==)
The additional . allows == to take two parameters, before passing the expression to bool.
Since the order of parameters is different, you need to use incif like this:
(flip . incif)
(Integrating that into incif is left as an exercise to the reader. [Translation: It’s not trivial, and I don’t yet know how. ;])
Remember that in Haskell list comprehensions, if conditionals can be used in the result clause or at the end. But, most importantly, guards without if can be used to filter results. I am using pairs from zip. The second of the pair is the list number. It stays constant while the elements of the list are being compared to the constant (k).
Your result [1,2,0] does not include list numbers 1, 2 or 3 because it is obvious from the positions of the sums in the result list. The result here does not add the occurrences in each list but list them for each list.
nocc k ls = [ z | (y,z) <- zip ls [1..length ls], x <- y, k == x]
nocc 1 [[1, 2], [2, 3, 2, 1, 1], [3]]
[1,2,2] -- read as [1,2,0] or 1 in list 1, 2 in list 2 and 0 in list 3
When you are writing slightly more complex functions I notice that $ is used a lot but I don't have a clue what it does?
$ is infix "application". It's defined as
($) :: (a -> b) -> (a -> b)
f $ x = f x
-- or
($) f x = f x
-- or
($) = id
It's useful for avoiding extra parentheses: f (g x) == f $ g x.
A particularly useful location for it is for a "trailing lambda body" like
forM_ [1..10] $ \i -> do
l <- readLine
replicateM_ i $ print l
compared to
forM_ [1..10] (\i -> do
l <- readLine
replicateM_ i (print l)
)
Or, trickily, it shows up sectioned sometimes when expressing "apply this argument to whatever function"
applyArg :: a -> (a -> b) -> b
applyArg x = ($ x)
>>> map ($ 10) [(+1), (+2), (+3)]
[11, 12, 13]
I like to think of the $ sign as a replacement for parenthesis.
For example, the following expression:
take 1 $ filter even [1..10]
-- = [2]
What happens if we don't put the $? Then we would get
take 1 filter even [1..10]
and the compiler would now complain, because it would think we're trying to apply 4 arguments to the take function, with the arguments being 1 :: Int, filter :: (a -> Bool) -> [a] -> [a], even :: Integral a => a -> Bool, [1..10] :: [Int].
This is obviously incorrect. So what can we do instead? Well, we could put parenthesis around our expression:
(take 1) (filter even [1..10])
This would now reduce to:
(take 1) ([2,4,6,8,10])
which then becomes:
take 1 [2,4,6,8,10]
But we don't always want to be writing parenthesis, especially when functions start getting nested in each other. An alternative is to place the $ sign between where the pair of parenthesis would go, which in this case would be:
take 1 $ filter even [1..10]
In Haskell, I can easily map a list:
map (\x -> 2*x) [1,2]
gives me [2,4]. Is there any "mapTuple" function which would work like that?
mapTuple (\x -> 2*x) (1,2)
with the result being (2,4).
Here's a rather short point-free solution:
import Control.Monad (join)
import Control.Arrow ((***))
mapTuple = join (***)
Searching at Hoogle gives no exact matches for (a -> b) -> (a, a) -> (b, b), which is the type you require, but it is pretty easy to do yourself:
mapTuple :: (a -> b) -> (a, a) -> (b, b)
mapTuple f (a1, a2) = (f a1, f a2)
Note, you will have to define a new function for 3-tuples, 4-tuples etc - although such a need might be a sign, that you are not using tuples like they were intended: In general, tuples hold values of different types, so wanting to apply a single function to all values is not very common.
You could use Bifunctor:
import Control.Monad (join)
import Data.Bifunctor (bimap)
join bimap (2*) (1,2)
This works not only for pairs, but for a number of other types as well, e.g. for Either.
Bifunctor is in base as of version 4.8. Previously it was provided by the bifunctors package.
You can also use lens to map tuples:
import Control.Lens
mapPair = over both
Or you can map over tuples with upto 10 elements:
mapNtuple f = traverseOf each (return . f)
You can use arrows from module Control.Arrow to compose functions that work on tuples.
Prelude Control.Arrow> let f = (*2) *** (*2)
Prelude Control.Arrow> f (1,2)
(2,4)
Prelude Control.Arrow> let f' = (*2) *** (*3)
Prelude Control.Arrow> f (2,2)
(4,4)
Prelude Control.Arrow> f' (2,2)
(4,6)
Your mapTuple then becomes
mapTuple f = f *** f
If with your question you asked for a function that maps over tuples of arbitrary arity, then I'm afraid you can't because they would have different types (e.g. the tuple types (a,b) and (a,b,c) are totally different and unrelated).
Here is another way:
mapPair :: (a -> b) -> (a, a) -> (b, b) -- this is the inferred type
mapPair f = uncurry ((,) `on` f)
You need Data.Function imported for on function.
To add another solution to this colourful set... You can also map over arbitrary n-tuples using Scrap-Your-Boilerplate generic programming. For example:
import Data.Data
import Data.Generics.Aliases
double :: Int -> Int
double = (*2)
tuple :: (Int, Int, Int, Int)
tuple = gmapT (mkT double) (1,2,3,4)
Note that the explicit type annotations are important, as SYB selects the fields by type. If one makes one tuple element type Float, for example, it wouldn't be doubled anymore.
Yes, for tuples of 2 items, you can use first and second to map the contents of a tuple (Don't worry about the type signature; a b c can be read as b -> c in this situation). For larger tuples, you should consider using a data structure and lenses instead.
The extra package provides the both function in the Data.Tuple.Extra module. From the docs:
Apply a single function to both components of a pair.
> both succ (1,2) == (2,3)
both :: (a -> b) -> (a, a) -> (b, b)
You can also use Applicatives which have additional benefit of giving you possibility to apply different functions for each tuple element:
import Control.Applicative
mapTuple :: (a -> a') -> (b -> b') -> (a, b) -> (a', b')
mapTuple f g = (,) <$> f . fst <*> g . snd
Inline version:
(\f -> (,) <$> f . fst <*> f . snd) (*2) (3, 4)
or with different map functions and without lambda:
(,) <$> (*2) . fst <*> (*7) . snd $ (3, 4)
Other possibility would be to use Arrows:
import Control.Arrow
(+2) . fst &&& (+2) . snd $ (2, 3)
I just added a package tuples-homogenous-h98 to Hackage that solves this problem. It adds newtype wrappers for tuples and defines Functor, Applicative, Foldable and Traversable instances for them. Using the package you can do things like:
untuple2 . fmap (2 *) . Tuple2 $ (1, 2)
or zip tuples like:
Tuple2 ((+ 1), (*2)) <*> Tuple2 (1, 10)
The uniplate package provides the descend function in the Data.Generics.Uniplate.Data module. This function will apply the function everywhere the types match, so can be applied to lists, tuples, Either, or most other data types. Some examples:
descend (\x -> 2*x) (1,2) == (2,4)
descend (\x -> 2*x) (1,"test",Just 2) == (2,"test",Just 4)
descend (\x -> 2*x) (1,2,3,4,5) == (2,4,6,8,10)
descend (\x -> 2*x) [1,2,3,4,5] == [2,4,6,8,10]
Yes, you would do:
map (\x -> (fst x *2, snd x *2)) [(1,2)]
fst grabs the first data entry in a tuple, and snd grabs the second; so, the line of code says "take a tuple, and return another tuple with the first and second items double the previous."