I am learning Haskell and I am having a hard time performing the following task.
I have a script that gives me a directory. I would like to call that script, get the directory and then use the "cd" in Turtle to change the directory. Below is the code that I currently wrote but it fail to compile.
It says lineToText targetDirLine
expects Line
and not Maybe Line
. I do not understand why fold (inshell "getSomeDir" empty) Fold.head
produces Maybe (Maybe Line)
.
Even after fixing this error I get other issue using cd
.
#!/usr/bin/env stack
-- stack --resolver lts-10.2 script
{-# LANGUAGE OverloadedStrings #-}
import qualified Control.Foldl as Fold
import Turtle
getDirAndCd :: MonadIO io => io ()
getDirAndCd = cd fp
where (Just targetDirLine) = fold (inshell "getSomeDir" empty) Fold.head
fp = fromText (lineToText targetDirLine)
What am I missing?
If you inspect the type of the fold
expression with GHCi:
λ> :t fold (inshell "getSomeDir" empty) Fold.head
fold (inshell "getSomeDir" empty) Fold.head
:: MonadIO io => io (Maybe Line)
you'll see that it's not a Maybe Line
, it's an io (Maybe Line)
. When you write, in your where
clause:
where Just targetDirLine = fold (inshell "getSomeDir" empty) Fold.head
it tries to match the Maybe
on the left with the io
on the right, and so io (Maybe Line)
unifies with Maybe (Maybe Line)
, and that's why you get the type error you do.
You'll want to process the fold
expression in a <-
line in the do
-block:
getDirAndCd :: (MonadIO io) => io ()
getDirAndCd = do
Just targetDirLine <- fold (inshell "getSomeDir" empty) Fold.head
let fp = fromText (lineToText targetDirLine)
cd fp
This will result in another error, Could not deduce (MonadFail io)
. The issue here is that Just targetDirLine <- ...
represents a pattern that could fail, if fold
returns a Nothing
. If you add a MonadFail io
constraint, it type checks:
{-# LANGUAGE OverloadedStrings #-}
import qualified Control.Foldl as Fold
import Turtle
getDirAndCd :: (MonadFail io, MonadIO io) => io ()
getDirAndCd = do
Just targetDirLine <- fold (inshell "getSomeDir" empty) Fold.head
let fp = fromText (lineToText targetDirLine)
cd fp