Как люди обычно разрабатывают модули Haskell?

Извините за несколько общий вопрос. Я новичок в Haskell, и я - тип человека, который учится, погружаясь в проблему и выясняя нужные предметы, когда я иду. Итак, я начал разрабатывать модуль Haskell, целью которого является простая линейная регрессия. Вот моя настройка каталога:

mymod/
- mymod.cabal
- src/
-- MyMod/
--- Linear.hs
--- Linear/
---- Regression.hs
--- Data.hs
--- Data/
---- Examples.hs
- tst/

Мой файл кэша выглядит следующим образом:

library
  exposed-modules:     MyLib.Linear, MyLib.Linear.Classifier, 
                       MyLib.Data, MyLib.Data.Examples
  build-depends:       base == 4.6.*
  hs-source-dirs:      src

В настоящее время я пишу модуль Examples, который по сути является файловым файлом CSV. Это выглядит так:

module Exampels (load) where

import Text.ParserCombinators.Parsec
import Control.Applicative

examples = line `endBy` eol
line = cell `sepBy` (char ',')

cell :: GenParser Char st Double
cell = rd <$> many1 (noneOf ",\n")
    where rd = read :: String -> Double

eol = char '\n'

load :: String -> Either ParseError [[Double]]
load input = parse examples "(unknown)" input

Это была первая часть системы, которую я написал. Я проверил это, используя ghci и :l Examples.hs из mylib/src/MyLib/Data/, а затем load "5\n" и проверил результат. Теперь я хочу начать писать регрессионную логику, но я хочу протестировать этот код в сочетании с парсером CSV, который я уже написал. Как люди обычно идут на тестирование кода, как это?

Например, в Java я обычно создавал новый пакет с классом, в котором есть основной метод. С Java это прямо для меня, потому что я понимаю, как работает classpath, и может направить компилятор для поиска моих классов, которые я хочу запустить. Как это сделать в Haskell?

Спасибо!

Ответ 1

По сути, существует четыре подхода: писать тесты, записывать исполняемые файлы, экспериментировать с REPL (GHCI) и записывать тесты. К счастью, последняя версия Cabal (1.18) поддерживает их все. Также для справки у меня есть проект, который показывает некоторые.

Испытания

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

Существуют три основные структуры: HUnit для модульного тестирования, QuickCheck для тестирования свойств и doctest для тестирования примеров из комментариев к документу. Существуют также купольные рамки, такие как HTF, который объединяет HUnit и QuickCheck и освобождает вас от некоторых из их шаблонов.

В Cabal вы можете определить тестовые пакеты как отдельные единицы компиляции с их собственными настройками. Вот пример. Затем вы можете запустить их с помощью cabal test.

Исполняемые

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

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

Вы можете запускать исполняемые файлы с помощью cabal run [name], где "name" указывает исполняемое имя, если есть необходимость устранить неоднозначность (т.е. когда у вас более одного).

REPL (GHCI)

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

Вы можете запустить GHCI в своем проекте с помощью cabal repl [name].

Бенчмарки

Критерий является единой доминирующей библиотекой для бенчмаркинга. Как и выше, вы можете объявить свои тестовые исполняемые файлы в cabal с помощью блока benchmark [name]. Затем вы можете запустить их с помощью cabal bench.