2013-10-26 2 views
0

Итак, скажем, у меня есть функция, которая берет строку и возвращает определенное значение этой строки, заданной текстовым файлом. Текстовый файл будет выглядеть следующим образом.другой haskell IO issue

привет - 2
свиданья - 3

поэтому функция вернет 2 дается "привет" и 3 дали "до свидания". Теперь функция типа Вес (я не могу изменить, так как это является частью системы):

type Weight = String -> Int 

Как реализовать такую ​​функцию, учитывая, что оно должно быть типа Вес. Проблема в том, что я не знаю, как сделать вес осведомленным о том, какое значение нужно вернуть с определенной строкой. Я не могу жестко задавать значения, потому что они будут разными в разных текстовых файлах. И я не могу прочитать read внутри этой функции или что-то в этом роде, не так ли? Есть ли другие варианты?

ответ

3

У вас есть два варианта,

assignWeight :: String -> IO Int 
assignWeight = do 
    file <- readFile whatever 

    -- parse file and extract a function assigning strings to their weights 
    return $ parseFile file 

Или

assignWeight :: String -> Weight 
assignWeight file = parseFileAndExtractWeights file 

, а затем прочитать файл в main и использования выделки. Так что не функция верхнего уровня, но мы все еще получаем нашу функцию позже, частично применяя assignWeight к содержимому файла

main = do 
    weights <- assignWeight `fmap` readFile whatever 
    -- use weights 

Но вы не можете выполнить IO в вычислении типа Weight, так что вы будете либо иметь выполнить его в другом месте и передать ему тип или просто изменить тип. Никакой другой способ.

+0

'ReadFile все, >> = возврат. assignWeight' может быть записано как 'assignWeight <$> readFile whatever'. – kqr

+0

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

+0

@ user2922609 Вы не можете. Haskell не разрешает такую ​​мутацию – jozefg

0

У вас не может быть assignWeight глобально, но вы можете иметь его локально с подлинным не-IO-типом, который вам нужен. Я думаю, что нижеприведенный подход является общей схемой, используемой для отделения монадического кода от немонодических.

import Data.Maybe 
import Control.Applicative 

parseFile :: IO [(String, Int)] 
parseFile = read <$> readFile "Parse.txt" 

main = do 
     content <- parseFile 
     let assignWeight x = fromJust $ lookup x content 
     print $ process assignWeight 

type Weight = String -> Int 

process :: Weight -> Int 
process x = 0 

Здесь assignWeight имеет правильный тип. Вы можете передать его: посмотрите, как я передал его в не монадическую функцию process. У вас не может быть assignWeight, определенного на верхнем уровне, не нарушая чистоты, как отмечали другие комментаторы, но иметь его локально и перемещаться - это широко используемый подход.

Вот более модульный подход:

getAssignWeight :: IO Weight 
getAssignWeight = do 
     content <- parseFile 
     let assignWeight x = fromJust $ lookup x content 
     return assignWeight 

main = do 
     assignWeight <- getAssignWeight 
     print $ process assignWeight