Передача случайно сгенерированного списка в качестве параметра в Haskell
Я новичок в Haskell и действительно испытываю проблемы со всем этим.
Я пытаюсь выяснить, сколько времени требуется, чтобы пройти список в haskell. Я хотел создать список случайных чисел и передать его в качестве параметра функции, чтобы я мог напечатать каждый элемент списка. Я использую пакет CRITERION для теста. Вот код:
{-# LANGUAGE OverloadedStrings #-}
import System.Random
import Control.Exception
import Criterion.Main
printElements [] = return ()
printElements (x:xs) = do print(x)
printElements xs
randomList 0 = return []
randomList n = do
x <- randomRIO (1,100)
xs <- randomList (n-1)
return (x:xs)
main = defaultMain [
bgroup "printElements" [ bench "[1,2,3]" $ whnf printElements (randomList 10)
, bench "[4,5,6]" $ whnf printElements [4,5,6,4,2,5]
, bench "[7,8,9]" $ whnf printElements [7,8,9,2,3,4]
, bench "[10,11,12]" $ whnf printElements [10,11, 12,4,5]
]
]
Ошибка при запуске кода:
listtraversal.hs:18:67:
Couldn't match expected type ‘[a0]’ with actual type ‘IO [t0]’
In the second argument of ‘whnf’, namely ‘(randomList 10)’
In the second argument of ‘($)’, namely
‘whnf printElements (randomList 10)’
1 ответ
Короче говоря, вам нужно привязать свою функцию к IO
значение, вместо того, чтобы пытаться применить его к значению, заключенному в IO
значение.
-- instead of whnf printElements (randomList 10)
randomList 10 >>= whnf printElements
randomList
не возвращает список значений; это возвращает IO
действие, которое при выполнении может создать список значений. Игнорируя различные ограничения, вызванные реализацией, тип
randomList :: (...) => t1 -> IO [t] -- not t1 -> [t]
Таким образом, вы не можете напрямую работать со списком значений, которые IO
действие может произвести; вам нужно использовать экземпляр монады, чтобы связать значение с соответствующей функцией. whnf printElements
одна такая функция; он берет список и возвращает IO
действие.
whnf printElements :: Show a => [a] -> IO ()
Вместо того, чтобы вытащить список и передать его whnf printElements
мы "запихиваем" функцию в IO
значение с использованием >>=
, Тип оператора, специализированный для IO
монада, это
(>>=) :: IO a -> (a -> IO b) -> IO b
В этом случае первый IO a
значение является IO [t]
значение, возвращаемое randomList
, whnf printElements
это a -> IO b
функция, с которой мы связываемся. Результат новый IO
значение, которое занимает первое IO
value извлекает упакованное значение, применяет данную функцию и возвращает результат.
Другими словами, IO
сама монада заботится о том, чтобы отделить результат от randomList
и применяя к нему свою функцию, а не явно.
(Вы могли заметить, что я сказал, что >>=
привязывает значение к функции и наоборот. Возможно, правильнее будет сказать, что >>=
связывает их вместе в один IO
действие).