Haskell, могу ли я вызвать функцию без вывода ввода-вывода, работающую с монадами? - PullRequest
4 голосов
/ 01 апреля 2012

Почему я не могу этого сделать?Запрещено использование «do» в этом вопросе: / Как я могу назвать words в моем списке и одновременно привести к IO?Спасибо .. это мой фактический код: /

main :: IO()
main = 
     putStr "Name of File: " >>
     getLine >>=
     \st ->
    openFile st ReadMode >>=
    \handle ->
        hGetContents handle >>=
        \y ->
        words y >>=
        \strings ->
            strings !! 1 >>=
            \string->
                 putStr string

[Редактировать] Решение:

main :: IO()
main = 
     putStr "Name of File: " >>
     getLine >>=
     \st ->
    openFile st ReadMode >>=
    \handle ->
        hGetContents handle >>=
        \y ->
        return (words y) >>=
        \strings ->
            return (strings !! 1) >>=
            \string->
                 putStr string

Ответы [ 2 ]

6 голосов
/ 01 апреля 2012

(Это не дает прямого ответа на вопрос, но сделает ваш код более идиоматичным и, следовательно, более легким для чтения.)

Вы часто используете шаблон \x -> f x >>= ..., это может (и должно быть)) быть исключенным: это (в основном) ненужный шум, который затемняет смысл кода.Я не буду использовать ваш код, так как это домашнее задание, но рассмотрим этот пример (обратите внимание, что я использую return, как подсказывает другой ответ):

main = getLine >>= 
         \fname -> openFile fname ReadMode >>= 
           \handle -> hGetContents handle >>= 
              \str -> return (lines str) >>= 
                \lns -> return (length lns) >>= 
                  \num -> print num

(он читает имя файла изпользователь, а затем печатает количество строк в этом файле.)

Самая простая оптимизация - это раздел, в котором мы подсчитываем количество строк (это соответствует той части, где вы разделяете слова и получаете второеодин): количество строк в строке str равно length (lines str) (что совпадает с length . lines $ str), поэтому у нас нет причин для вызова length и вызова lines отдельный.Наш код теперь:

main = getLine >>= 
         \fname -> openFile fname ReadMode >>= 
           \handle -> hGetContents handle >>= 
              \str -> return (length . lines $ str) >>= 
                \num -> print num

Теперь следующая оптимизация на \num -> print num.Это можно записать как print.(Это называется эта конвертация ).(Вы можете думать об этом как о «функции, которая принимает аргумент и вызывает print для него, аналогично самой print»).Теперь у нас есть:

main = getLine >>= 
         \fname -> openFile fname ReadMode >>= 
           \handle -> hGetContents handle >>= 
              \str -> return (length . lines $ str) >>= print

Следующая оптимизация, которую мы можем сделать, основана на законах монады .Используя первый, мы можем превратить return (length . lines $ str) >>= print в print (length . lines $ str) (т. Е. «Создать контейнер, содержащий значение (это делается с помощью return), а затем передать это значение в print так же, как просто передатьзначение до print ").Опять же, мы можем удалить скобки, поэтому мы имеем:

main = getLine >>= 
         \fname -> openFile fname ReadMode >>= 
           \handle -> hGetContents handle >>= 
              \str -> print . length . lines $ str

И посмотрите!У нас есть eta-преобразование, которое мы можем сделать: \str -> print . length . lines $ str становится просто print . length . lines.Это оставляет:

main = getLine >>= 
         \fname -> openFile fname ReadMode >>= 
           \handle -> hGetContents handle >>= print . length . lines

На этом этапе мы, вероятно, можем остановиться, так как это выражение намного проще, чем наше первоначальное (мы могли бы продолжать, используя >=>, если мыхотеть).Поскольку это намного проще, его также легче отлаживать (представьте, если бы мы забыли использовать lines: в оригинальном main это было бы не очень понятно, в последнем это очевидно.)

В вашем коде вы можете и должны делать то же самое: вы можете использовать такие вещи, как section (что означает \x -> x !! 1, то же самое, что (!! 1)), а также законы eta-преобразования и монады Iиспользуется выше.

6 голосов
/ 01 апреля 2012

Используйте return (words y) вместо words y. return оборачивает чистое значение (например, [String], возвращаемое words) в монаду.

Судя по вашей формулировке, этот вопрос - домашнее задание. Если это так, он должен быть помечен как таковой.

...