Apply a function to a file if it exists - haskell

I have a function that apply a function to a file if it exists:
import System.Directory
import Data.Maybe
applyToFile :: (FilePath -> IO a) -> FilePath -> IO (Maybe a)
applyToFile f p = doesFileExist p >>= apply
where
apply True = f p >>= (pure . Just)
apply False = pure Nothing
Usage example:
applyToFile readFile "/tmp/foo"
applyToFile (\p -> writeFile p "bar") "/tmp/foo"
A level of abstraction can be added with:
import System.Directory
import Data.Maybe
applyToFileIf :: (FilePath -> IO Bool) -> (FilePath -> IO a) -> FilePath -> IO (Maybe a)
applyToFileIf f g p = f p >>= apply
where
apply True = g p >>= (pure . Just)
apply False = pure Nothing
applyToFile :: (FilePath -> IO a) -> FilePath -> IO (Maybe a)
applyToFile f p = applyToFileIf doesFileExist f p
That allow usages like:
applyToFileIf (\p -> doesFileExist p >>= (pure . not)) (\p -> writeFile p "baz") "/tmp/baz"
I have the feeling that I just scratched the surface and there is a more generic pattern hiding.
Are there better abstractions or more idiomatic ways to do this?

applyToFileIf can be given a more generic type and a more generic name
applyToIf :: Monad m => (a -> m Bool) -> (a -> m b) -> a -> m (Maybe b)
applyToIf f g p = f p >>= apply
where
apply True = g p >>= (return . Just)
apply False = return Nothing
In the type of applyToIf we see the composition of two Monads
Maybe is a monad ---v
applyToIf :: Monad m => (a -> m Bool) -> (a -> m b) -> a -> m (Maybe b)
^------------- m is a monad -------------^
When we see the composition of two monads, we can expect that it could be replaced with a monad transformer stack and some class describing what that monad transformer adds. The MaybeT transformer replaces m (Maybe a)
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
And adds MonadPlus to what an m can do.
instance (Monad m) => MonadPlus (MaybeT m) where ...
We'll change the type of applyToIf to not have a composition of two monads and instead have a MonadPlus constraint on a single monad
import Control.Monad
applyToIf :: MonadPlus m => (a -> m Bool) -> (a -> m b) -> a -> m b
applyToIf f g p = f p >>= apply
where
apply True = g p
apply False = mzero
This could be rewritten in terms of guard from Control.Monad and given a more generic name.
guardBy :: MonadPlus m => (a -> m Bool) -> (a -> m b) -> a -> m b
guardBy f g p = f p >>= apply
where
apply b = guard b >> g p
The second g argument adds nothing to what guardBy can do. guardBy f g p can be replaced by guardBy f return p >>= g. We will drop the second argument.
guardBy :: MonadPlus m => (a -> m Bool) -> a -> m a
guardBy f p = f p >>= \b -> guard b >> return p
The MaybeT transformer adds possible failure to any computation. We can use it to recreate applyToIf or use it more generally to handle failure through complete programs.
import Control.Monad.Trans.Class
import Control.Monad.Trans.Maybe
applyToIf :: Monad m => (a -> m Bool) -> (a -> m b) -> a -> m (Maybe b)
applyToIf f g = runMaybeT . (>>= lift . g) . guardBy (lift . f)
If you instead rework the program to use monad style classes, it might include a snippet like
import Control.Monad.IO.Class
(MonadPlus m, MonadIO m) =>
...
guardBy (liftIO . doesFileExist) filename >>= liftIO . readFile

Related

Implementing Applicative's (<*>) for Monad

Applicative's has the (<*>) function:
(<*>) :: (Applicative f) => f (a -> b) -> f a -> f b
Learn You a Haskell shows the following function.
Given:
ap :: (Monad m) => m (a -> b) -> m a -> m b
ap f m = do
g <- f -- '<-' extracts f's (a -> b) from m (a -> b)
m2 <- m -- '<-' extracts a from m a
return (g m2) -- g m2 has type `b` and return makes it a Monad
How could ap be written with bind alone, i.e. >>=?
I'm not sure how to extract the (a -> b) from m (a -> b). Perhaps once I understand how <- works in do notation, I'll understand the answer to my above question.
How could ap be written with bind alone, i.e. >>= ?
This is one sample implementation I can come up with:
ap :: (Monad m) => m (a -> b) -> m a -> m b
ap xs a = xs >>= (\f -> liftM f a)
Of if you don't want to even use liftM then:
ap :: (Monad m) => m (a -> b) -> m a -> m b
ap mf ma = mf >>= (\f -> ma >>= (\a' -> return $ f a'))
Intially these are the types:
mf :: m (a -> b)
ma :: m a
Now, when you apply bind (>>=) operator to mf: mf >>= (\f-> ..., then f has the type of:
f :: (a -> b)
In the next step, ma is also applied with >>=: ma >>= (\a'-> ..., here a' has the type of:
a' :: a
So, now when you apply f a', you get the type b from that because:
f :: (a -> b)
a' :: a
f a' :: b
And you apply return over f a' which will wrap it with the monadic layer and hence the final type you get will be:
return (f a') :: m b
And hence everything typechecks.

How to lift function to transformed monad in haskell?

I know with the data constructor and the run*** function,
I can lift any function to a specific MonadTrans instance.
Like this,
import Control.Monad.Trans
import Control.Monad.Trans.Maybe
import Control.Monad
liftF :: (Monad m) => (a -> b) -> MaybeT m a -> MaybeT m b
liftF f x = MaybeT $ do
inner <- runMaybeT x
return $ liftM f inner
But how can I generalize this liftF to
liftF :: (MonadTrans t, Monad m) => (a -> b) -> t m a -> t m b
As #thoferon mentioned, you can just use liftM:
import Control.Monad.Trans
import Control.Monad.Trans.Maybe
import Control.Monad (liftM)
liftF :: (Monad m) => (a -> b) -> MaybeT m a -> MaybeT m b
liftF f m = liftM f m
liftF' :: (MonadTrans t, Monad m, Monad (t m)) => (a -> b) -> t m a -> t m b
liftF' f m = liftM f m
(I had to add an additional Monad constraint to liftF').
But why would you do this? Check out the source code for MaybeT -- there's already a Monad instance:
instance (Monad m) => Monad (MaybeT m) where
fail _ = MaybeT (return Nothing)
return = lift . return
x >>= f = MaybeT $ do
v <- runMaybeT x
case v of
Nothing -> return Nothing
Just y -> runMaybeT (f y)
And actually, as liftM is the same as Functor's fmap:
instance (Functor m) => Functor (MaybeT m) where
fmap f = mapMaybeT (fmap (fmap f))
You can find similar instances for all the transformers.
Is this what you are asking? Can you provide some more concrete examples that show what you're trying to do and why, and in what way the existing Functor and Monad instances fail to meet your needs?

How best to type "Any monad transformer stack containing m"

I'd like to write the function
fixProxy :: (Monad m, Proxy p) => (b -> m b) -> b -> () -> p a' a () b m r
fixProxy f a () = runIdentityP $ do
v <- respond a
a' <- lift (f a)
fixProxy f a' v
which works just like you'd think until I try to run the proxy
>>> :t \g -> runRVarT . runWriterT . runProxy $ fixProxy g 0 >-> toListD
(Num a, RandomSource m s, MonadRandom (WriterT [a] (RVarT n)),
Data.Random.Lift.Lift n m) =>
(a -> WriterT [a] (RVarT n) a) -> s -> m (a, [a])
where I use RVarT intentionally to highlight the existence of the Lift class in RVar. Lift represents the existence of a natural transformation n :~> m which ought to encapsulate what I'm looking for, a function like:
fixProxy :: (Monad m, Monad n, Lift m n, Proxy p)
=> (b -> m b) -> b -> () -> p a' a () b n r
Is Lift the right answer (which would require many orphan instances) or is there a more standard natural transformation MPTC to use?
Note the practical solution, as described in comments below, is something like
runRVarT . runWriterT . runProxy
$ hoistK lift (fixProxy (const $ sample StdUniform) 0) >-> toListD

Strict fmap using only Functor, not Monad

One irritation with lazy IO caught to my attention recently
import System.IO
import Control.Applicative
main = withFile "test.txt" ReadMode getLines >>= mapM_ putStrLn
where getLines h = lines <$> hGetContents h
Due to lazy IO, the above program prints nothing. So I imagined this could be solved with a strict version of fmap. And indeed, I did come up with just such a combinator:
forceM :: Monad m => m a -> m a
forceM m = do v <- m; return $! v
(<$!>) :: Monad m => (a -> b) -> m a -> m b
f <$!> m = liftM f (forceM m)
Replacing <$> with <$!> does indeed alleviate the problem. However, I am not satisfied. <$!> has a Monad constraint, which feels too tight; it's companion <$> requires only Functor.
Is there a way to write <$!> without the Monad constraint? If so, how? If not, why not? I've tried throwing strictness all over the place, to no avail (following code does not work as desired):
forceF :: Functor f => f a -> f a
forceF m = fmap (\x -> seq x x) $! m
(<$!>) :: Functor f => (a -> b) -> f a -> f b
f <$!> m = fmap (f $!) $! (forceF $! m)
I don't think it's possible, and also the monadic forceM doesn't work for all monads:
module Force where
import Control.Monad.State.Lazy
forceM :: Monad m => m a -> m a
forceM m = do v <- m; return $! v
(<$!>) :: Monad m => (a -> b) -> m a -> m b
f <$!> m = liftM f (forceM m)
test :: Int
test = evalState (const 1 <$!> undefined) True
And the evaluation:
Prelude Force> test
1
forceM needs a strict enough (>>=) to actually force the result of its argument. Functor doesn't even have a (>>=). I don't see how one could write an effective forceF. (That doesn't prove it's impossible, of course.)

Is this function possible?

findM :: Monad m => (a -> m Bool) -> m [a] -> Maybe (m a)
I cannot implement it by myself. I could use some pointers
find looks like:
find f as = listToMaybe $ filter f as
so I tried:
findM f as = filterM f as >>= listToMaybe
but it doesnt work.
No. It is not possible. However, you can write a function with the signature:
findM :: Monad m => (a -> m Bool) -> m [a] -> m (Maybe a)
The reason it is not possible is because in order to figure out if the Maybe has constructor Just x or Nothing, you have to get the value out of the monad. Which means that the Maybe must be inside the monad at the end, since it is not possible in general to extract a value from inside a monad. (That is the whole point of monads, after all.)
For example, given your signature to findM, you could write some obviously incorrect functions:
findM :: Monad m => (a -> m Bool) -> m [a] -> Maybe (m a)
findM = magic
anyM :: Monad m => (a -> m Bool) -> m [a] -> Bool
anyM f = isJust . findM f
extractBool :: Monad m => m Bool -> Bool
extractBool = anyM id . liftM (:[])
The function extractBool is obviously impossible, so findM cannot have that signature.
Here is an implementation of findM:
findM :: Monad m => (a -> m Bool) -> [a] -> m (Maybe a)
findM _ [] = return Nothing
findM f (x:xs) = do y <- f x
if y then return (Just x) else findM f xs
I am not sure of a simpler way to implement it -- this seems fairly clean, and it works on infinite lists.
Changing the signature from using an m [a] to using [a] makes it more useful and easier to use. You'll quickly figure out why, if you implement both interfaces.
Try
findM :: Monad m => (a -> m Bool) -> [a] -> m (Maybe a)
findM p = foldr step (return Nothing)
where
step x r = do
b <- p x
if b then return (Just x) else r
This version only uses the predicate as much as it has to, whereas the filterM version uses it on every element. So for example:
ghci> let findM' p xs = filterM p xs >>= return . listToMaybe
ghci> let check x = putStrLn ("checking " ++ show x) >> doesDirectoryExist x
ghci> findM check ["test1", ".", "test2"]
checking "test1"
checking "."
Just "."
ghci> findM' check ["test1", ".", "test2"]
checking "test1"
checking "."
checking "test2"
Just "."
Others have already demonstrated that this isn't possible, however with a further constraint you can get a very similar function.
findM :: (Traversable m, Monad m) => (a -> m Bool) -> m [a] -> Maybe (m a)
findM p xs = Data.Traverse.sequence $ dietrichsFindM p xs
Not every Monad has a Traversable instance, but if it does this will work.
For the signature
findM :: Monad m => (a -> m Bool) -> m [a] -> m (Maybe a)
i suggest:
import Control.Monad
import Data.Maybe
findM :: Monad m => (a -> m Bool) -> m [a] -> m (Maybe a)
findM f m = m >>= filterM f >>= return . listToMaybe
or
findM :: Monad m => (a -> m Bool) -> m [a] -> m (Maybe a)
findM = ((return . listToMaybe =<<) .) . (=<<) . filterM
for a point-free style.

Resources