Конструкция do в Haskell
Я пытаюсь изучить Haskell и хочу написать небольшую программу, которая выводит содержимое файла на экран. Когда я загружаю его в GHCi, я получаю следующую ошибку:
Последнее утверждение в конструкции do должно быть выражением
Я знаю, что этот вопрос уже задавался здесь: Haskell - "Последнее утверждение в конструкции" do "должно быть выражением".
Хотя мой код очень похож, я до сих пор не могу понять проблему. Если бы кто-нибудь мог указать мне на проблему, я был бы очень благодарен.
module Main (main) where
import System.IO
import System(getArgs)
main :: IO()
main = do
args <- getArgs
inh <- openFile $ ReadMode head args
printFile inh
hClose inh
printFile :: Handle -> IO ()
printFile handle = do
end <- hIsEOF handle
if end
then return ()
else do line <- hGetLine handle
putStrLn line
printFile handle
4 ответа
Ваш отступ сломан. Это лучше:
printFile :: Handle -> IO ()
printFile handle = do
end <- hIsEOF handle
if end
then return ()
else do line <- hGetLine handle
putStrLn line
printFile handle
printFile :: Handle -> IO ()
printFile handle = do
end <- hIsEOF handle
if end
then return ()
else do
line <- hGetLine handle
putStrLn line
printFile handle
Имея if
дальше с отступом, чем end <- hIsEof handle
на самом деле это было продолжение строки, а не последующее действие в do
, Точно так же тот факт, что у вас было putStrLn line
менее отступ, чем line <- hGetLine handle
означает, что do
(внутри else
) закончилась там.
Есть серьезные проблемы. Во-первых, if
отступ слишком далеко - end <- ...
Предполагается, что последняя строка do
, Unindent...
следующий вопрос выходит. То же сообщение об ошибке, только в строке 18. На этот раз строки 19 и 20 не имеют глубоких отступов (они не анализируются как часть do
). Отступ (в любом случае выглядит лучше, так как все теперь выстраивается)... следующее сообщение об ошибке. Хорошей новостью является то, что на этот раз это не ошибка отступа, и исправление снова тривиально.
test.hs:9:22:
Couldn't match expected type `([a] -> a) -> [String] -> FilePath'
against inferred type `IOMode'
In the second argument of `($)', namely `ReadMode head args'
In a stmt of a 'do' expression:
inh <- openFile $ ReadMode head args
In the expression:
do { args <- getArgs;
inh <- openFile $ ReadMode head args;
printFile inh;
hClose inh }
Исправление inh <- openFile (head args) ReadMode
, Если вы хотите получить более подробное объяснение, почему / как ваша версия неверна или что означает ошибка, дайте мне знать, и я отредактирую.
Это ты написал:
main :: IO()
main = do
args <- getArgs
inh <- openFile $ ReadMode head args
printFile inh
hClose inh
Но это, вероятно, лучше, как это:
main :: IO()
main = do
args <- getArgs
withFile (head args) ReadMode printFile
Вы всегда можете использовать явные скобки с { ; }
никогда не беспокоиться об этой глупости.
printFile :: Handle -> IO ()
printFile handle = do {
end <- hIsEOF handle ;
if end
then return ()
else do { line <- hGetLine handle ;
putStrLn line ;
printFile handle }}
было бы полностью нормально (как в, не вызывает ошибку).
Ввод / вывод обрабатывается через специальныйdo
"язык, в Haskell. Следует принять. То, что это на самом деле реализуется через монады, является деталью реализации.
Чтобы уточнить: я не думаю, что скобки лучше, я думаю, что они должны идти вместе с красивым и последовательным отступом. Скобки дают нам хорошие и непосредственные визуальные подсказки относительно структуры кода. Дикие отступы, конечно, будут бесполезным отвлечением большую часть времени. Кроме того, фигурные скобки дают нам гарантию на работоспособность кода и избавляют нас от бессмысленных забот о случайных ситуациях. Они удаляют эту хрупкость.