Странное возвращение в Хаскеле - PullRequest
3 голосов
/ 15 августа 2011
checkstring :: [String] -> Int -> [String]
checkstring p n = do    z <- doesFileExist (p !! n)
    if z
    then p
    else error $ "'" ++ (p !! n) ++ "' file path does not exist"

Он проверяет наличие элемента в строке, посмотрев на «n» (поэтому, если n = 2, он проверит наличие второй строки в списке), а затем проверит, существует ли он.Если он существует, он вернет исходный список строк, если нет, то будет ошибка. Почему он это делает?:

Couldn't match expected type `[t0]' with actual type `IO Bool'
    In the return type of a call of `doesFileExist'
    In a stmt of a 'do' expression: z <- doesFileExist (p !! n)

Ответы [ 3 ]

6 голосов
/ 15 августа 2011

Тип doesFileExist равен String -> IO Bool. Если ваша программа хочет знать, существует ли файл, она должна взаимодействовать с файловой системой, что является действием ввода-вывода. Если вы хотите, чтобы ваша функция checkString делала это, она также должна иметь какой-то тип на основе ввода-вывода. Например, я думаю, что-то подобное будет работать, хотя я не пробовал:

checkstring :: [String] -> Int -> IO [String]
checkstring p n = do    z <- doesFileExist (p !! n)
    if z
    then return p
    else error $ "'" ++ (p !! n) ++ "' file path does not exist"
2 голосов
/ 15 августа 2011

Добавить к тому, что MatrixFrog упомянул в своем ответе. Если вы посмотрите на сигнатуру вашей функции, т.е. [String] -> Int -> [String], это означает, что эта функция является чистой функцией и не имеет побочных эффектов, где, как и в вашем теле функции, вы используете doesFileExist, который имеет сигнатуру String -> IO Bool, где Наличие IO указывает на то, что это нечистая функция, то есть включает в себя некоторое IO. В haskell существует строгое разделение между нечистыми и чистыми функциями, и на самом деле, если ваша функция вызывает какую-то другую функцию, которая нечиста, чем ваша функция, она также нечиста. Так что в вашем случае ваша функция checkString должна быть нечистой, и это можно сделать, вернув ей значение IO [String], о чем MatrixFrog упомянул в своем ответе.

С другой стороны, я бы посоветовал вам сделать функцию примерно такой:
checkString :: String -> IO (Maybe String), поскольку вашей функции не нужен весь список строк, поскольку ей просто нужна определенная строка из списка, чтобы выполнить свою работу, и вместо того, чтобы выдавать ошибку, вы можете использовать Maybe, чтобы обнаружить ошибку. Это всего лишь предложение, но оно также зависит от того, как используется ваша функция.

0 голосов
/ 15 августа 2011

Думаю, проблема в том, что ваша сигнатура типа заставляет блок do предполагать, что это какая-то другая монада. Например, предположим, что вы работаете в монаде списка. Тогда вы можете написать

myFcn :: [String] -> Int -> [String]
myFcn p n = do
    return (p !! n)

В случае монады списка, return просто возвращает одноэлементный список, так что вы получаете поведение, подобное,

> myFcn ["a", "bc", "d"] 1
["bc"]

(Мое личное мнение таково, что было бы очень полезно, если бы GHC имел возможность распечатывать типичные ошибки, которые могут вызвать ошибку типа; я сочувствую спрашивающему в том, что я получил много сообщений об ошибках типа, которые найдите время, чтобы выяснить).

...