Я читаю http://learnyouahaskell.com/ ... И что-то меня удивило:
Из-за этого main
всегда имеет сигнатуру типа main :: IO something
, где something
это какой-то конкретный тип.
?То есть main
не обязательно должен быть типа IO()
, а может быть IO(String)
или IO(Int)
?Но какая польза от этого?
Я немного поиграл ...
m@m-X555LJ:~$ cat wtf.hs
main :: IO Int
main = fmap (read :: String -> Int) getLine
m@m-X555LJ:~$ runhaskell wtf.hs
1
m@m-X555LJ:~$ echo $?
0
m@m-X555LJ:~$
Хмм.Итак, моя первая гипотеза опровергнута.Я думал, что это был способ для программы на Haskell вернуть статус завершения в оболочку, подобно тому, как программа на C запускается с int main()
и сообщает о состоянии выхода с помощью return 0
или return 1
.
Но нет: вышеприведенная программа потребляет 1
от ввода и затем ничего не делает, и, в частности, похоже, не возвращает это 1
в оболочку.
Еще один тест:
m@m-X555LJ:~$ cat wtf.hs
main = getContents
m@m-X555LJ:~$ runhaskell wtf.hs
m@m-X555LJ:~$
Wow.На этот раз я попытался вернуть IO String
.По неизвестным мне причинам на этот раз Хаскелл не даже не ждет ввода, как это было, когда я возвращал IO Int
.Программа, похоже, просто ничего не делает.
Это намекает на то, что значение действительно нигде не возвращается: очевидно, поскольку результаты getContents
нигде не используются, вся инструкция была пропущена из-за лени.Но если это было так, почему возврат IO Int
не был пропущен?Ну да: я сделал fmap read
на действии IO
;но, похоже, применимо то же самое, вычисление read
необходимо только в том случае, если используется результат действия, который - как намекнул пример main = getContents
- не используется, поэтому лень следует также пропустить read
иследовательно также getLine
, верно?Ну, неправильно - но я запутался, почему.
Какой смысл возвращать IO Something
из main
, а не только IO ()
?