Haskell - хотите глобальную переменную из файла, который не изменяется

type Anagrams = Map String [String]

buildAnagrams :: IO Anagrams
buildAnagrams = do
          list <- readCSV "mydict.csv"
          return $ foldr f Map.empty list
            where
             f :: String -> Anagrams -> Anagrams
             f s = Map.insertWith (++) (sort s) [s]

У меня есть эта функция, которая создает карту для поиска анаграмм из файла словаря, который не изменяется. Я хочу иметь карту в качестве глобальной переменной, так как она должна использоваться другими функциями. В настоящее время функции используют unsafePerformIO в buildAnagrams, но я знаю, что это не рекомендуется. Вся программа также очень медленная, поскольку она строит карту несколько раз. Должен быть лучший способ сделать это?

1 ответ

Решение

Если вы хотите сохранить данные анаграммы во внешнем файле, вам нужно IO, чтобы прочитать их. Итак, у вас есть несколько вариантов:

  • передача данных анаграммы в качестве дополнительного аргумента для всех ваших функций
  • передать те же данные, используя неявный аргумент
  • обернуть все в Reader монада (или добавить ReaderT трансформатор)
  • использование unsafePerformIO с обычными оговорками

Около unsafePerformIO: если вы абсолютно уверены, что прочитанный вами файл не изменится, это один из его "безопасных" вариантов использования. Хотя это и не рекомендуется, либо элегантно, оно может решить эту проблему. Чтобы избежать повторного чтения данных, вы должны использовать

{-# NOINLINE allAnagrams #-}
allAnagrams :: Anagrams
allAnagrams = unsafePermformIO buildAnagrams

так что внешний файл будет прочитан ровно один раз.

Другой вариант - включить внешний файл в исходный код на Haskell. Это можно сделать несколькими способами, в том числе

  • простое метапрограммирование: вы пишете программу, которая берет ваш внешний файл и конвертирует его в файл.hs, который объявляет большой вектор строки
  • Шаблон Haskell: тот же эффект, что и метапрограммирование, но немного более элегантный
Другие вопросы по тегам