Как работает monadicIO

У меня есть следующий код

fastShuffle :: [a] -> IO [a]
fastShuffle a = <some code>

prop_fastShuffle_correct :: [Int] -> Property
prop_fastShuffle_correct s =  
  monadicIO ( do
    sh <- run (fastShuffle s) 
    return ( True ==> ( insertionSort sh == insertionSort s  && 
                        if length s > 10 
                          then s /= sh 
                          else True ) ) )

И.. это работает. Я не могу понять, как то, что выглядит как чистая функция (prop_fastShuffle_correct), может вызывать не чистую функцию с побочными эффектами (fastShuffle).

Надеюсь, что кто-то может объяснить.

Спасибо!


person Tomer    schedule 05.03.2020    source источник
comment
Я не очень хорошо знаком с QuickCheck, но, глядя на определение Property, похоже, что Property включает в себя конструктор, который хранит значение IO.   -  person bradrn    schedule 05.03.2020
comment
В библиотеках есть несколько типов, которые внутренне используют IO в своем определении. Из-за этого они могут разрешить функцию типа monadicIO, выполняющую действие IO и возвращающую тип библиотеки. Property QuickCheck является одним из этих типов: он должен использовать IO в своем (непрозрачном) определении, иначе QuickCheck никогда не сможет протестировать действия ввода-вывода, подобные вашему fastShuffle.   -  person chi    schedule 05.03.2020
comment
вы должны включить все свои операторы импорта, чтобы сделать код полным и воспроизводимым сам по себе.   -  person Will Ness    schedule 10.03.2020


Ответы (1)


Функции в Haskell никогда не имеют побочных эффектов.

Есть только значения с побочными эффектами, например getLine (значение, а не функция). getLine - это инструкция "прочитать строку текста из стандартного в". Это не функция, которая выполняет инструкцию, это сама инструкция.

И putStrLn не является функцией, которая выводит текст в стандартный вывод. putStrLn — это функция, которая принимает строку в качестве параметра и возвращает инструкцию для записи этой строки в стандартный вывод.

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

person user253751    schedule 05.03.2020
comment
Я бы хотел, чтобы все ответы монад были такими. - person Will Ness; 10.03.2020
comment
@WillNess на самом деле это не монада, это IO вещь. List, например, является монадой, но значения списка не являются действиями. - person user253751; 11.03.2020
comment
разделение вычисления и вычисления (оценки) является вещью монады (ну, на самом деле, вещью функтора). недетерминированные вычисления просто моделируются чистыми [] вычислениями. значение [1,2] :: [Int] является (принимается за) инструкцией для недетерминированного получения значения, равного либо 1, либо 2 (согласно этой интерпретации), точно так же, как return 1 :: IO Int является инструкцией для «очевидной вещи». - person Will Ness; 11.03.2020