Передача случайно сгенерированного списка в качестве параметра в 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 действие).

Другие вопросы по тегам