Проблема типа чтения файла в Haskell - PullRequest
1 голос
/ 21 декабря 2009

У меня проблемы с системой типов Haskell.

Положение:

  • Следующая программа принимает список имен файлов в командной строке
  • Для всего имени файла он читает его содержимое, используя функцию readFile
  • Содержимое каждого файла передается в inputParser (Parsec)
  • Отдых не так важен
  • Основная проблема в функции read_modules
  • Первые два выражения выражения 'do' недопустимы в системе типов Haskell
  • Проблема в конфликте между [String] x IO String x [Char] x ...
  • Функция 'parse' должна принимать String, но когда она ее получает, она внезапно хочет IO String (с тем же аргументом), в противном случае она хочет String

Что я хочу:

  1. Прочитать содержимое каждого файла
  2. Передать это содержимое функции 'parse' в качестве третьего аргумента

Вот код.

module Main where

import System.IO
import System.Environment
import Text.ParserCombinators.Parsec
import InputParser
import Data

usage :: IO ()
usage = putStrLn "Usage: x file file file option"

parse_modules :: String -> [Char] -> Either ParseError [Module]
parse_modules filename input = parse inputParser filename input

read_modules :: [String] -> [Module]
read_modules [] = []::[Module]
read_modules (filename:rest) =
  do
    content <- readFile filename -- HERE is the problem
    modules <- case parse_modules filename content of -- HERE is problem too
      Left error -> do
        putStr "parse error at "
        print error
      Right out -> out ++ (read_modules rest)
    return modules

use :: [String] -> IO ()
use args =
  do
    init <- last args
    filenames <- take (length args - 1) args
    modules <- read_modules filenames
    return ()

main :: IO ()
main = do args <- getArgs
          if length args < 2
            then usage
            else use args

Вот ошибки вывода GHC

ghc --make -o x.hs input-parser.hs data.hs
[3 of 3] Compiling Main             ( x.hs, x.o )

x.hs:19:4:
    Couldn't match expected type `IO String'
           against inferred type `[String]'
    In a stmt of a 'do' expression: content <- readFile filename
    In the expression:
        do content <- readFile filename
           modules <- case parse_modules filename content of {
                        Left error -> do ...
                        Right out -> out ++ (read_modules rest) }
           return modules
    In the definition of `read_modules':
        read_modules (filename : rest)
                       = do content <- readFile filename
                            modules <- case parse_modules filename content of {
                                         Left error -> ...
                                         Right out -> out ++ (read_modules rest) }
                            return modules
-- THIS ERROR is somewhat not important
x.hs:30:4:
    Couldn't match expected type `[Char]'
           against inferred type `IO Char'
      Expected type: String
      Inferred type: IO Char
    In a stmt of a 'do' expression: init <- last args
    In the expression:
        do init <- last args
           filenames <- take (length args - 1) args
           modules <- read_modules filenames
           return ()
make: *** [x] Error 1

В чем проблема:

  • Я не могу понять, что я должен пройти где. Я вроде знаю, чего хочу, но не понимаю синтаксиса или стиля.
  • Я Haskell Greenie (здесь не решается)
  • ВИДЫ

Какие вопросы:

  • Как мне исправить проблему с представленным типом? Что я должен поместить в функцию «разбора»? Что мне дает readFile? Эти два типа совместимы? Разве нет необходимости в каком-либо преобразовании?

Соответствующие ссылки:

Спасибо всем за ваши советы и комментарии.

Ответы [ 3 ]

4 голосов
/ 21 декабря 2009

Прежде всего, поскольку ваша функция read_module s выполняет ввод / вывод, она должна возвращать что-то типа IO. Это означает, что вы должны изменить ряд вещей в вашей функции:

  1. Пустой кейс должен использовать return
  2. Ветвь Right в выражении case должна использовать do-notation
  3. При рекурсивном вызове сама функция должна делать это в нотации

Вот (надеюсь) исправленная версия вашей read_modules функции:

read_modules :: [String] -> IO [Module]
read_modules [] = return []
read_modules (filename:rest) =
  do
    content <- readFile filename -- HERE is the problem
    modules <- case parse_modules filename content of -- HERE is problem too
      Left error -> do
        putStr "parse error at "
        print error
      Right out -> do 
        more <- read_modules rest
        return (out ++ more)
    return modules

Я не проверял, но надеюсь, что это поможет вам в пути.

3 голосов
/ 21 декабря 2009

Это неправильно.

read_modules :: [String] -> [Module]

Должно быть

read_modules :: [String] -> IO [Module]

Это не все, что вам нужно исправить, но это поможет вам.

2 голосов
/ 22 декабря 2009

Вот что вызвало другую ошибку, которую вы назвали менее важной:

use :: [String] -> IO ()
use args =
  do
    init <- last args

Оператор <- используется в блоке do для извлечения чего-либо, содержащегося в монаде (в данном случае IO), чтобы вы могли работать с фактическим значением, захваченным внутри. Но args здесь имеет тип [String], а не IO [String], поэтому вам не нужно этого делать; вы уже вытащили список аргументов из IO с arg <- getArgs в main.

Если вы хотите присвоить немонадное значение временной переменной внутри блока do, используйте вместо нее let, например:

let x = last args

Похоже, вы делаете ту же ошибку и в нескольких других местах, а не только в этой строке. Необходимость по-разному относиться к монадическим и немонадным значениям, когда вы просто хотите создать временную переменную внутри своей функции, легко запутать кого-то, кто плохо знаком с языком.

Кстати, init - это имя функции в стандартной библиотеке, поэтому вы можете использовать другое имя переменной.

...