Why does my function give me an out of scope error?
tarefa1 :: [String] -> [String]
tarefa1 linhas = if res == ok then ["OK"] else [show res]
where
(tab,coords) = parteMapa conteudo
erro1 = validaTabuleiro 1 tab
erro2 = validaCoords (length tab + 1) tab coords
res = juntaErro erro1 erro2
The error:
Not in scope: `conteudo'.
conteudo is supposed to be a .txt document that I have in a different file, but I don't know how to make it to load it in this function.
This is not really a good question, since this should be covered by basic Haskell knowledge, and it's clearly homework for those of us who can speak Portuguese. You shouldn't be afraid to ask your teacher for some help, and I'm sure he would be glad to give you that.
Nevertheless, since it is possible to answer the question, I will:
Input and Output in Haskell is only possible inside functions that evaluate an IO action (that is, a value of the IO type).
Of course, since main has type IO (), you can execute IO actions inside of it.
The simplest way to read a file is with the readFile function. It accepts a FilePath and evaluates to a IO String (which has the full contents of the file). I'll give you an example and I hope you can follow from it.
main :: IO ()
main = do
contents <- readFile "yourfilename.txt" -- because I used "<-", contents has type String
let fileLines = lines contents -- here I have a [String] with each line of the file
someFunction fileLines
return ()
someFunction should also evaluate an IO action, in this example. You can "put things inside" IO using return, in case you don't know.
Related
In particular I want to use pure Haskell functions on the results on console input. I'm curious if exists something like ? operator from rust.
this snippet complains that words expect the type String, while its supplied wrapped into an io action. But i can't even use >>= operator since as far as i understand i cannot instantiate IO constructor directly. So, does it mean all the standard library functions can't work with io even in the scope of io action?
thing :: IO ()
thing = do
let mbwords = words $ getLine ;
Since Haskell is not designed to be totally useless, there must be a way. And there is more than one indeed.
What you looking for is something like this
main = do
line <- getLine
let mbwords = words line
or perhaps
main = do
mbwords <- fmap words getLine
Note you use <- to "open" the monadic value inside the do-block, not let.
Also note instantiating IO constructors is not necessary as long as you have functions that return IO actions, such as print. You can express the same idea with
main = fmap words getLine >>= print
(of course you can use an arbitrary action of the right type instead of print).
I am wiriting simple application which has functionality of saving/loading its current state.
Save function looks as below:
doSave :: BoardType -> Field -> [Char] -> Bool
doSave board player fileName = do
let x = encodeFile fileName (board :: BoardType, player :: Field)
True -- there will be exception handling
And my load function:
doLoad :: [Char] -> IO (BoardType, Field)
doLoad fileName = decodeFile fileName :: IO (BoardType, Field)
And there's my problem, after loading, I have IO (BoardType, Field) which does not fit my program and other functions which probably should not accept IO parameters. If I have followed this IO escalation, there would be all IOs in my application - is it necessary (or - normal in haskell language)?
And finally - is there a simple way I can get rid of this IO?
It takes a little while to get used to.
Some monads let you extract the "inner value" after some work, but IO never does.
There is no way that e.g. returning the system time can ever be "pure" so any calculations you make with it need to remain wrapped in IO.
However, that doesn't mean most of your code lives in IO-land.
main = do
(bt, fld) <- doLoad "somefilename"
let bResult = doSomethingPureWithBoard bt
let fResult = doSomethingPureWithField fld
let bt2 = updateBoard bt bResult fResult
doSave "someFilename" bt2 fld -- This should also be in IO
You can always call pure functions from IO, just not the other way around. The <- gives you the "unwrapped" values while you are in an IO function. Actually it's passing the results as parameters to the next "statement" - google around "de-sugaring do notation" and similar.
is it necessary (or - normal in haskell language)
Your application will typically have an outer wrapper of IO actions, beginning with main :: IO () and the repeatedly restricted code that has less and less privledges, until you're only dealing with pure code.
I have been playing around with Haskell for a bit now but I have not fully grasped how to use third party functions that run inside a Monad. Every time I go back to reading articles about Monads, etc. I get a good understanding but when it comes to applying them to real-world code, I cannot figure why a piece of code does not work. I resort to trial and error and usually get it to compile but I feel I should be able to use them properly the first time without trying to go through my heuristic of changes (try let, <-, liftM, etc.)
So I would like to ask a few questions based on this simple function, which admittedly does a lot of interesting things.
import Text.XML.HXT.Core
import Text.HandsomeSoup
import Data.String.Utils
function h = do
let url = myUrlBuilder h
doc = fromUrl url
res = runX $ doc >>> css "strong" /> getText
--nres = liftM rmSpaceAndBang (res)
res
rmSpaceAndBang ps = map (\x-> replace "!" "" (strip x)) ps
The above code compiles. I have purposefully left out the type declarations as what I thought it should be doesn't compile. So here are my questions.
Why can I not do res <- runX ... and return res that way?
Why should res be inside a let statement and not be bound the result of action? As I understand it, do x <- a1; a2 is equivalent to a1 >>= \x -> a2. How is that different when you let x = a1?
When I used <- I got the following error and if not for my trial and error approach I would not have been able to figure out that I need to use let here.
Couldn't match type `[]' with `IO'
Expected type: IO String
Actual type: [String]
While I focused on res above, my lack of understanding applies to other let statements in the function as well.
How do I find the return type of res?
I couldn't figure out a way to search hackage for getText (hxt seems too big to look through module by module. Probably will try Google site search next time). In the end, I ended up typing up some parts of the code in GHCi and did :t res. It told me it is [String]. Is there a better way to do this?
Since res is of type [String] I thought I will put [String] as the return type for my function. But GHC says it should be IO [String] (compiles). Why did :t give me the wrong information first?
When functions return IO String, what's the best way to use pure functions on them?
Now that I am stuck inside IO [String] I need to use to lift everywhere I do string operations. Is there a better way to do this?
Hopefully I will learn enough from this that I will be able to use right syntax without resorting to blindly trying a few combinations.
Update:
The key piece I was missing was the fact res is not a value but rather an action. So I have 2 choices: one is is my above code with let res = but call it at the end and the other is to do res <- but then do return (res).
The advantage of using res <- is that I can get rid of the liftM as res is now [String] (see #duplode's answer below).
Thanks!
In your code, res is an IO [String]. I do not doubt that you got [String] through GHCi at first, but I believe you tested it with
>>> res <- runX $ doc >>> css "strong" /> getText
>>> :t res
res :: [String]
Which is not equivalent to your code. The difference is that let just binds your IO [String] action without running it, while <- in a do block runs the action and binds the result, in this case a [String].
Now that I am stuck inside IO [String] I need to use to lift
everywhere I do string operations. Is there a better way to do this?
Within a do block, sometimes it is more convenient to write:
res <- runX $ doc >>> css "strong" /> getText
return $ rmSpaceAndBang res
Which is strictly equivalent to using liftM (or fmap):
liftM rmSpaceAndBang $ doc >>> css "strong" /> getText
For a fast answer, let doesn't run anything, it's just makes the lhs as a synonym for rhs.
You actually need a monadic function inside the do for computation be executed.
main = do
let func = print "I need to be called"
print "I don't need to be called"
func
outputs:
"I don't need to be called"
"I need to be called"
So res in your code is not a value, it's a monadic action/function.
Remember that <- is tied to >>=, and requires a a -> m b on the rhs.
let has no requirements.
I'm trying to do some programming in Haskell. I'm trying to read a file and then put every line in the file in a list by using the line function. Here's the partial code:
file = "muh.rtr"
readTrack :: String -> Track
readTrack file =
do let defFile = readFile file
let fileLines = lines defFile
However, I keep getting this error:
Parser.hs:22:39:
Couldn't match expected type `String' with actual type `IO String'
In the first argument of `lines', namely `defFile'
In the expression: lines defFile
In an equation for `fileLines': fileLines = lines defFile
I have been searching the Internet for hours now hoping to find some answers somewhere but I've not been so lucky so far.
You probably wanted either something like this:
readTrack :: String -> IO Track
readTrack file = do defFile <- readFile file
let fileLines = lines defFile
-- etc....
...or something like this:
readTrack :: String -> IO Track
readTrack file = do fileLines <- liftM lines (readFile file)
-- etc....
But what you really should do is stop, go find an introduction to the language such as Learn You a Haskell, and spend some time reading it.
Feeding code consisting entirely of very simple errors into GHC and then posting the error message on Stack Overflow is not a good way to learn.
The type of readFile is
readFile :: FilePath -> IO String
so you need to use <- to bind the result, and your function has to return IO Track.
readTrack :: String -> IO Track
readTrack file =
do defFile <- readFile file
let fileLines = lines defFile
...
I suggest reading a good tutorial on IO in Haskell, for example the Input and Output chapter of Learn You a Haskell for Great Good!.
readFile return an IO string. That is, it is an IO computation that returns a string. This means that you need to use <- instead of let to "get" the string its returning.
readTrack file =
do
defFile <- readFile file
...
You can use let to bind things that are not IO computations, such as the return value of lines, that is a regular string.
readTrack file =
do
defFile <- readFile file
let fileLines = lines defFile
...
Finally, you need to return the value you might want to try something like
readTrack file =
do
defFile <- readFile file
let fileLines = lines defFile
fileLines --Doesn't actually work!
but unfortunately, since we are inside a "do" block and are trying to return a monadic computation, we need to send the fileLines back into the io monad (remember, out function returns IO [String], not String!
readTrack file =
do
defFile <- readFile file
let fileLines = lines defFile
return fileLines
Note that the "return" here is not a return statement as would normaly be found in most languages and it should not be used in your pure functions.
All this might seem like a lot at first. I would suggest you stick to pure functions (without input and output / monads) until until you get a better hang on the language.
You can't do it like that -- you've run into the IO monad. What you need to do is something like:
readTrack :: String -> IO Track
readTrack file = do
defFile <- readFile file
let fileLines = lines deffile
...
return whatever
Think of IO T values as statements (as opposed to expressions) with return type T. Because statements have side effects, but expressions don't, you can never turn a statement into an expression; the type system enforces this, which is why your type signature won't work.
Note the different assignment-like syntax in the do block: in this example, the foo <- bar is used for IO operations, while the let baz = quux syntax is used for purely functional evaluation. This is more fallout from using monadic I/O -- it makes more sense in the full generality of Haskell's polymorphic type system, but it's not necessarily bad to have a syntactic indicator of pure vs. side-effecting operations, either.
In general, it is good practice to try keeping most of your implementation in the purely functional realm: implement your pure computation with regular functional methods, then describe your I/O operations in the IO monad. It is a common novice mistake to write loops in the IO monad which would be more appropriate as list comprehensions or recursive functions.
If your function is supposed to have type readTrack :: String -> Track, are you sure the String is a filename? Perhaps it's data - if so, don't use readFile. Write some sample data and test using that, eg
sampleData = "2 3\n1 30 234 45\n1 2 32 4\n5 3 4 23"
(The other question on SO about this homework didn't use file IO. I'll not link to it because you're in a crisis and might be tempted to copy, and in any case if you refuse to learn haskell at least I'll force you to improve your StackOverflow search skills! :) )
In any case I think you'll get more marks by solving the String problem than by solving the IO problem.
Delay the readFile issue until you've got the pure version working, otherwise you might end up writing most of your code in the IO monad which would be much more complex than necessary.
One you have a pure function readTrack :: String -> Track, you can do
readTrackFrom :: FilePath -> IO Track
readTrackFrom filename = fmap readTrack (readFile filename)
Now, fmap :: Functor f => (a -> b) -> f a -> f b, so takes pure functions and lifts them to work in a different computational context like IO.
Since IO is a Functor (look it up tomorrow, not tonight), we're using it as the type (String -> Track) -> IO String -> IO Track. That's good because readTrack :: String -> Track and (readFile filename) :: IO String.
If you want to, you can then >>= print or >>= writeFile newfilename as you see fit.
Don't forget to add deriving Show after use data Track =..., but you don't need to if you're using type Track = .....
I want to write functions and put result to string.
I want function:
read' :: FilePath -> String
I use:
:t readFile
readFile :: FilePath -> IO String
I make:
read' :: IO ()
read' = do
str <- readFile "/home/shk/workspace/src/test.txt"
putStrLn str
I want to ask str is string or not?
We know that:
:t putStrLn
putStrLn :: String -> IO ()
Then why i can't:
read' :: String
read' = do
str <- readFile "/home/shk/workspace/lxmpp/src/test.txt"
str
I get error that:
Couldn't match expected type `[t0]' with actual type `IO String'
In the return type of a call of `readFile'
In a stmt of a 'do' expression:
str <- readFile "/home/shk/workspace/lxmpp/src/test.txt"
In the expression:
do { str <- readFile "/home/shk/workspace/src/test.txt";
str }
Thank you.
Just to quibble a bit more, while the other answers are perfectly correct, I want to emphasize something: Something with the type IO String isn't just a string that the type system won't let you get at directly. It's a computation that performs I/O to get a string for you. Applying readFile to a file path doesn't return a String value any more than putting a steak next to a meat grinder magically turns them into a hamburger.
When you have some code like this:
foo = do let getStr = readFile "input.txt"
s1 <- getStr
s2 <- getStr
-- etc.
That doesn't mean you're "taking the string out of getStr twice". It means you're performing the computation twice and can easily get different results between the two.
I think no one has answered this, very important question, yet:
I want to ask str is string or not?
I will try to.
The type of the variable str is String, yes.
However, the scope of this variable is very limited. I think desugaring the do-notation is necessary for understanding:
read' = readFile "/home/shk/workspace/src/test.txt" >>= (\str -> putStrLn str)
I think here it becomes more clear why str is not good enough. It is an argument of the function you pass to >>=. Its value only becomes available when someone calls your function, which happens only when the IO action containing it is being executed.
Also, the type of read' :: IO () is determined not so much by the putStrLn str, but rather by the return type of the operator >>=. Have a look at it (specialized to the IO monad):
(>>=) :: IO a -> (a -> IO b) -> IO b
You can see that the result is always an IO b action, so trying to change any of arguments won't help.
You can read some monad tutorial if you want to understand why the type is the way it is. The intuition behind it is: you can't perform an action without performing an action.
And on the practical side of the question, to use the value returned by some action, instead of trying to do use (extractValue inputAction), which does not make sense because extractValue is not possible, try inputAction >>= use if your use does involve I/O, or fmap use inputAction if it does not.
You should use return str in read' if you want it to return str instead of (). You can't strip IO from the type of read', since it's not a pure function. To get a better grip on how input/output in Haskell works I recommend you to read a tutorial.
As a more detailed reason why: It allows impurity.
You absolutely can not perform IO during a pure operation, or it would completely break referential transparency. Technically you can use unsafePerformIO but it would break referential transparency in this case - you should only use that if you can guarantee that the result is always the same.