In a file I am saving a file path. I want to read the file path from a file and then convert it to a variable, so everytime I run a function it gets the current file path from the file and then I can use this String in another function. I know variables are immutable but is there a way I can do it?
Here as you can see I am trying to read the file path from the file and then check if it is correct:
checksForCdCommand dir = checkIfPathExists constructedPath $ concat' $ paths sample2 where
constructedPath = do
let file = "abc.txt"
contents <- readFile file
return (if contents /= "/" then contents ++ "/" ++ dir else contents ++ dir)
Here if the contents is "/" it means that its my root dir so thats why I have this if else clause. But this way the code wont compile due to the following:
* Couldn't match expected type `[Char]'
with actual type `IO [Char]'
* In the first argument of `checkIfPathExists', namely
`constructedPath'
In the expression: checkIfPathExists constructedPath
In the expression:
checkIfPathExists constructedPath $ concat' $ paths sample2
I want to do something like this:
checksForCdCommand dir = checkIfPathExists constructedPath $ concat' $ paths sample2 where
constructedPath = if currDir /= "/" then currDir ++ "/" ++ dir else currDir ++ dir
where currDir
always has the value from the file.
The idea is that I have a tree that represents a file system and with the func paths I get all of the paths to the children, with checkIfPathExists
I pass a String as an argument to see if it's part of all the paths and I am doing a command that is like the cd unix command and when I change directories I save the current dir in the file.
I need this current directory for other things and that's why I need to read it from a file and then change the variable currDir
so I can use it for other functions.
change the variable currDir
This is the thing you can't do. All the rest is distracting window-dressing. If your approach relies fundamentally on doing this, you need a new approach. At some point, in an IO action, you need to read the contents of this abc.txt
file, and save that result into a variable. Then you pass that variable (whose value will not change.) to other functions, If at some point you want to "refresh" that variable. you will need to re-read it and use that new variable.
For example:
addOneToFileContents :: String -> Maybe (Int, Int)
addOneToFileContents c = case reads c of
[(x, _)] -> Just $ (x, x + 1)
_ -> Nothing
main = do
num <- readFile "abc.txt"
case addOneToFileContents num of
Nothing -> putStrLn "abc.txt should contain a number" *> main
Just (x, y) -> putStrLn $ show x ++ " + 1 = " ++ show y
This program is not very well written, but it demonstrates the basic idea. It assumes abc.txt exists; if not, you get some error. But assuming it does, it prints error messages very quickly until you (in another process) modify abc.txt to contain a number.
You will have to structure your program in a similar way: some IO action, probably in main
or close to it, reads the relevant file. Then it's passed to some other function, which makes decisions about what to do based on the file contents. Later, you re-read the file in main
and continue the loop.
There are tools that make this process simpler; for example, you can use Reader to plumb the contents of abc.txt through the pure parts of your program. It's not really much simpler in isolation, but it combines more cleanly with other bookkeeping you may have to do, like plumbing the results of additional IO actions through. But fundamentally it's no different: you have to do IO in IO actions, and variables don't change.
"I know variables are immutable but is there a way I can do it?"
Haskell is very opinionated on the subject of mutable variables - they don't exist, only immutable values exist. Like dominoes, the output of one function is plumbed into the input of the next function. The only changeable things are the values input at the start, and the values that come out of the end, like a sausage machine. It is possible to save values using the state monad, or by using a database, but if you are using a file as an improvised mutable variable then this savours strongly of attempting to subvert the principles of immutability.
But what about this 'Python' code?
let file = "abc.txt"
contents <- readFile file
It looks like there are mutable variables happening here, but this is an illusion. This is syntactic sugar which Haskell turns into a sequence of linked lambda expressions.
The error message is caused because you are using the do
syntactical sugar:
* Couldn't match expected type `[Char]'
with actual type `IO [Char]'
In the absence of your type declaration, which you should really provide, Haskell believes two things:
do
and return
means that you are doing an IO action
, type IO [Char]
, where [Char]
means a string of textconcat'
hence expected type is [Char]
, a stringSo, it is confused.
There are two things that you need to know about the IO action.
Hence my recommendations are:
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.