readFile :: FilePath -> IO String - file readwriteFile :: FilePath -> String -> IO () - write to filegetArgs :: IO [String] - getting command line arguments (from the System.Environment module)putStrLn :: String -> IO () - output a string, and carry over a string after it, to the console main :: IO ()
main = do
src <- readFile "file.in"
writeFile "file.out" (operate src)
operate :: String -> String
operate = ... is your function
main :: IO ()
main = do
x1 <- expr1
x2 <- expr2
...
xN <- exprN
return ()
do keyword, then the sequence of instructions xI <- exprI , and everything ends with return () . In each instruction to the left of the arrow is a sample (most often just a variable) of some type t , and to the right is an expression of the type IO t . Pattern-related variables can be used in subsequent instructions. If you want to use an expression whose type is different from IO t , then you need to write xI <- return (exprI) . The function return :: a -> IO a takes any value and wraps it into type IO. main :: IO ()
main = do
[arg1, arg2] <- getArgs
src <- readFile arg1
res <- return (operate src)
_ <- writeFile arg2 res
return ()
operate is still a pure function. In the first line after do command line arguments are extracted using pattern matching. The second line reads the file whose name is specified in the first argument. The third line uses return for a pure value of operate src . The fourth line writes the result to a file. This does not give any useful result, so we ignore it by writing _ <- ._ <- x you can simply write x .<- ) on the last but one line and the expression is of type IO () , then the last line with return () can be deleted.x <- return y can be replaced by let x = y (if you do not use variable names again). main :: IO ()
main = do
[arg1, arg2] <- getArgs
src <- readFile arg1
let res = operate src
writeFile arg2 res
main function has the IO type, but we can create new functions of this type to avoid repeating the code. For example, we can write a helper function to print beautiful headings: title :: String -> IO ()
title str = do
putStrLn str
putStrLn (replicate (length str) '-')
putStrLn ""
main : main :: IO ()
main = do
title "Hello"
title "Goodbye"
return x value of , we write the return x line in the last line of the do block. Unlike the return in imperative languages, this return must be on the last line. readArgs :: IO (String, String)
readArgs = do
xs <- getArgs
let x1 = if length xs> 0 then xs !! 0 else "file.in"
let x2 = if length xs> 1 then xs !! 1 else "file.out"
return (x1, x2)
main :: IO ()
main = do
(arg1, arg2) <- readArgs
src <- readFile arg1
let res = operate src
writeFile arg2 res
if we can choose which actions to perform. For example, if the user has not entered any arguments, we can report this: main :: IO ()
main = do
xs <- getArgs
if null xs then do
putStrLn "You entered no arguments"
else do
putStrLn ("You entered" ++ show xs)
do block is to do if , and continue with do in each of its branches. The only subtle point is that else must indent at least one space more than if . This is widely regarded as an error in the definition of Haskell, but for the moment, this additional space is indispensable.title above, we can write: main :: IO ()
main = do
let x = title "Welcome"
x
x
x
<- , we put the IO value itself into the variable x . x is of type IO () , so now we can write in a string to perform the action recorded in it. By writing x three times, we perform this action three times.IO values ​​as arguments to functions. In the previous example, we performed the action title "Welcome" three times, but how could we execute it fifty times? We can write a function that takes an action and a number, and performs this action the appropriate number of times: replicateM_ :: Int -> IO () -> IO ()
replicateM_ n act = do
if n == 0 then do
return ()
else do
act
replicateM_ (n-1) act
main :: IO ()
main = do
let x = title "Welcome"
replicateM_ 3 x
for statement in imperative languages ​​allows you to do the same thing as the replicateM_ function, but Haskell's flexibility allows you to define new control instructions — a very powerful tool. The replicateM_ function defined in Control.Monad is similar to ours, but more general; so you can use it instead of our version.IO values ​​are passed as an argument, so it’s not surprising that we can put them in data structures, such as lists and tuples. The sequence_ function takes a list of actions and executes them in turn: sequence_ :: [IO ()] -> IO ()
sequence_ xs = do
if null xs then do
return ()
else do
head xs
sequence_ (tail xs)
sequence_ finishes work with return () . If there are any elements in the list, sequence_ selects the first action with head xs and executes it, and then calls sequence_ on the rest of the tail xs list. Like replicateM_ , sequence_ already present in Control.Monad in a more general form. Now you can easily rewrite replicateM_ using sequence_ :replicateM_ :: Int -> IO () -> IO () replicateM_ n act = sequence_ (replicate n act)
null/head/tail . If there is exactly one instruction in the do block, the word do can be removed. For example, in the definition of sequence_ this can be done after the equal sign and after then . sequence_ :: [IO ()] -> IO ()
sequence_ xs =
if null xs then
return ()
else do
head xs
sequence_ (tail xs)
if with a mapping, as in any similar situation, without worrying about IO : sequence_ :: [IO ()] -> IO ()
sequence_ [] = return ()
sequence_ (x: xs) = do
x
sequence_ xs
main :: IO ()
main = do
xs <- getArgs
sequence_ (map operateFile xs)
operateFile :: FilePath -> IO ()
operateFile x = do
src <- readFile x
writeFile (x ++ ".out") (operate src)
operate :: String -> String
operate = ...
main and operateFile are part of the shell, and operate and all the functions that it uses are clean. As a general design principle, try to make the action layer as thin as possible. The shell should briefly perform the necessary input, and the main work should be assigned to the clean part. Using explicit I / O in Haskell is necessary, but it should be kept to a minimum — pure Haskell is much prettier.Source: https://habr.com/ru/post/80396/
All Articles