I'm learning Haskell and I'm trying to figure out why I'm getting an error on the following piece of code. I'm trying to define a function that can read a file at a given location, and perform some function on it, but it has an error that I'm afraid I can't get my head around.
I imagine I'm doing something stupid but I can't figure out what; can someone tell me?
readAndProcessFile :: String -> (String -> a) -> a
readAndProcessFile l f = do
contents <- readFile l -- error here
let result = f contents
return result
I get the error:
Occurs check: cannot construct the infinite type: a ~ IO a
In a stmt of a 'do' block: contents <- readFile l
In the expression:
do contents <- readFile l
let result = (f contents)
return result
In an equation for ‘readAndProcessFile’:
readAndProcessFile l f
= do contents <- readFile l
let result = ...
return result
• Relevant bindings include
f :: String -> a
readAndProcessFile :: String -> (String -> a) -> a
the type of readAndProcessFile is String -> (String -> a) -> IO a. Indeed, you use a do block, so that means it is monadic. What you here basically write is readFile >>= \contents -> let result = f contents in return result. The readFile furthermore specializes this to an IO.
You can simplify the expression by making use of <$> :: Functor f => (a -> b) -> f a -> f b
readAndProcessFile :: FilePath -> (String -> a) -> IO a
readAndProcessFile l f = f <$> readFile l
Related
I'm trying to extract "a" and the error "b" from an expression of the type IO (Either a b).
I have this function, which returns a parsed file based on the file path
readFile' :: FilePath -> IO (Either a b)
And that's the way I'm trying to extract the values of a and b:
rFile :: FilePath -> String
rFile f = do
l <- readFile' f
case l of
Right n -> show n
Left m -> show m
This is the error message:
Couldn't match type `IO' with `[]'
Expected type: [Either a b]
Actual type: IO (Either a b)
* In a stmt of a 'do' block: l <- readFile' f
rFile can't return a String value, only an IO String value. (Or more precisely, the result of the do construct must be an IO String value, not a String.)
rFile :: FilePath -> IO String
rFile f = do
l <- readFile' f
return $ case l of
Right n -> show n
Left m -> show m
You can use fmap and either to get rid of both the explicit case analysis and the do syntax.
rFile f = fmap (either show show) (readFile' f)
(The obvious follow-up question, how do I get a String from an IO String, is one I'm not going to rehash here. For all practical intents and purposes, you don't.)
This is a repost of my previous question(deleted by myself) since I considered it would be adequate to change the focus by presenting the sample code below.
Basically, I try to implement a Functor that takes a function such as id, \a -> a + 1 or even print .
So the function type can be
f :: a -> b
f :: a -> IO ()
module Main where
import Control.Monad.Primitive (PrimMonad (PrimState))
import qualified Data.Vector.Mutable as M
import System.IO.Error (isDoesNotExistErrorType)
main :: IO ()
main = do
let ioA = io (5 :: Int)
let f = print
-- f = \a -> a + 1
let ioB = someFunctor f ioA
ioB
print "done"
data R a = R
{ val :: M.MVector (PrimState IO) a
}
io :: a -> IO (R a)
io = \a -> do
val <- M.new 1
M.write val 0 a
return $ R val
_val :: R a -> IO a
_val = \ra -> M.read (val ra) 0
someFunctor :: Show a => (a -> b) -> IO (R a) -> IO (R b)
someFunctor = \f -> \ioA -> do
print "-- someFunctor"
val <- ioA >>= _val
print val --works 5
let ioB = io $ f val
--here, I want to actually `print val` when `f == print`
return $ f val
ioB
Output
"-- someFunctor"
5
"done"
The current sample code woks without errors, and what I want to achieve is to evaluate
f val
where
f val is the value wrapped into the new container ioB: io $ f val
However, due to the lazy-evaluation strategy of Haskell or some other reason, when f == print, this is not actually performed, so the val is not printed against my expectation.
So far, I did return $ f val, but this does not work unlike the working print val.
Just f val in do thread doesn't go well because f can be id and in that case, it's not IO type. Type mismatch. The compiler smartly generates an error here thanksfully.
So, my question is what is the generic way to implement f val to be evaluated when f == print f :: a -> IO ()?
If you want to do IO, you have to admit you're doing IO.
someFunctor :: Show a => (a -> IO b) -> IO (R a) -> IO (R b)
someFunctor = \f -> \ioA -> do
{- ... -}
b <- f val
io b
You can lift non-IO functions to IO ones with return, as in
someFunctor (return . id)
Although I feel like a have a good understanding of Haskel IO and Monads, I am having a hard time understanding the following error message.
Consider the following simple function in Haskell
testf :: Show a => a -> String
testf x = show x
I tried implementing a variant that prints to the console by using an IO Monad
printtoscreen :: Show a => a -> IO()
printtoscreen x = putStrLn . show x
However, this yields the following error:
Couldn't match type ‘[Char]’ with ‘a0 -> String’
Expected type: a0 -> String
Actual type: String
The correct version should omit explicitly stating the x parameter
printtoscreen :: Show a => a -> IO()
printtoscreen = putStrLn . show
I understand why the last code snippet works, but I cannot make sense out of the error message of the second code snippet, considering that it will also return a string to putStrLn
So why should the xparameter be omitted in the IO() variant?
., the function composition operator, expects a function. show x however is not a function; it's an evaluated value (of type [Char]) by the time it's given to ..
You'd have to use the function application operator instead:
printtoscreen x = putStrLn $ show x
So why should the x parameter be omitted in the IO () variant?
This has nothing to do with IO () itself. You here use function composition. Indeed, the (.) :: (b -> c) -> (a -> b) -> a -> c function is defined as:
(.) :: (b -> c) -> (a -> b) -> a -> c
(.) f g x = f (g x)
It is thus used to combine two functions f and g in a new function that first applies g to a parameter, and then f to the result of g x.
If you write:
printtoscreen x = putStrLn . show x
then the (.) function will resolve this to:
printtoscreen x = \y -> putStrLn (show x y)
or thus easier to read:
printtoscreen x y = putStrLn (show x y)
This would mean that show should have a type Show a => a -> b -> String, but it has type show :: Show a => a -> String, hence the error.
I am writing the Monad instance for a parser, and in trying to implement bind I am encountering some type checking errors. The following code does not type check:
(=<<) :: (a -> Parser b) -> Parser a -> Parser b
f =<< p = P (\s -> let x = parse p s
in if isErrorResult x
then x
else let (Result i a) = x
in parse (f a) i)
GHCi complains that the last line of code parse (f a) i is expecting type ParseResult b but received type ParseResult a. However, if I remove the error checking code then everything type checks just fine:
f =<< p = P (\s -> let x = parse p s
in let (Result i a) = x
in parse (f a) i)
So what is it about the if-then-else expression that causes the type confusion?
Compare:
data Boring a = Boring
doesn'tTypeCheck :: Boring a -> Boring b
doesn'tTypeCheck x = x
doesTypeCheck :: Boring a -> Boring b
doesTypeCheck Boring = Boring
Your situation is analogous: though your error result x probably doesn't actually have any a values inside, its type is still tagged with a. You'll need to "retag" it with b. It's probably cleanest to do this by switching from if to a case statement, as in
case parse p s of
Error e {- :: ParseResult a -} -> Error e {- :: ParseResult b -}
Result i a -> parse (f a) i
I'm learning Haskell, and writing a short parsing script as an exercise. Most of my script consists of pure functions, but I have two, nested IO components:
Read a list of files from a path.
Read the contents of each file, which, in turn, will be the input for most of the rest of the program.
What I have works, but the nested IO and layers of fmap "feel" clunky, like I should either be avoiding nested IO (somehow), or more skillfully using do notation to avoid all the fmaps. I'm wondering if I'm over-complicating things, doing it wrong, etc. Here's some relevant code:
getPaths :: FilePath -> IO [String]
getPaths folder = do
allFiles <- listDirectory folder
let txtFiles = filter (isInfixOf ".txt") allFiles
paths = map ((folder ++ "/") ++) txtFiles
return paths
getConfig :: FilePath -> IO [String]
getConfig path = do
config <- readFile path
return $ lines config
main = do
paths = getPaths "./configs"
let flatConfigs = map getConfigs paths
blockConfigs = map (fmap chunk) flatConfigs
-- Parse and do stuff with config data.
return
I end up dealing with IO [IO String] from using listDirectory as input for readFile. Not unmanageable, but if I use do notation to unwrap the [IO String] to send to some parser function, I still end up either using nested fmap or pollute my supposedly pure functions with IO awareness (fmap, etc). The latter seems worse, so I'm doing the former. Example:
type Block = [String]
getTrunkBlocks :: [Block] -> [Block]
getTrunkBlocks = filter (liftM2 (&&) isInterface isMatchingInt)
where isMatchingInt line = isJust $ find predicate line
predicate = isInfixOf "switchport mode trunk"
main = do
paths <- getPaths "./configs"
let flatConfigs = map getConfig paths
blockConfigs = map (fmap chunk) flatConfigs
trunks = fmap (fmap getTrunkBlocks) blockConfigs
return $ "Trunk count: " ++ show (length trunks)
fmap, fmap, fmap... I feel like I've inadvertently made this more complicated than necessary, and can't imagine how convoluted this could get if I had deeper IO nesting.
Suggestions?
Thanks in advance.
I think you want something like this for your main:
main = do
paths <- getPaths "./configs"
flatConfigs <- traverse getConfig paths
let blockConfigs = fmap chunk flatConfigs
-- Parse and do stuff with config data.
return ()
Compare
fmap :: Functor f => (a -> b) -> f a -> f b
and
traverse :: (Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b)
They are quite similar, but traverse lets you use effects like IO.
Here are the types again specialized a little for comparison:
fmap :: (a -> b) -> [a] -> [b]
traverse :: (a -> IO b) -> [a] -> IO [b]
(traverse is also known as mapM)
Your idea of 'nestedness' is actually a pretty good insight into what monads are. Monads can be seen as Functors with two additional operations, return with type a -> m a and join with type m (m a) -> m a. We can then make functions of type a -> m b composable:
fmap :: (a -> m b) -> m a -> m (m b)
f =<< v = join (fmap f v) :: (a -> m b) -> m a -> m b
So we want to use join here but have m [m a] at the moment so our monad combinators won't help directly. Lets search for m [m a] -> m (m [a]) using hoogle and our first result looks promising. It is sequence:: [m a] -> m [a].
If we look at the related function we also find traverse :: (a -> IO b) -> [a] -> IO [b] which is similarly sequence (fmap f v).
Armed with that knowledge we can just write:
readConfigFiles path = traverse getConfig =<< getPaths path