Передача случайно сгенерированного списка в качестве параметра в Haskell - PullRequest
0 голосов
/ 22 мая 2018

Я новичок в 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 Ответ

0 голосов
/ 22 мая 2018

Короче говоря, вам нужно связать вашу функцию со значением 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, мы «проталкиваем» функцию в an *Значение 1027 * с использованием >>=.Тип этого оператора, специализированный для монады IO, равен

(>>=) :: IO a -> (a -> IO b) -> IO b

. В этом случае первое значение IO a - это значение IO [t], возвращаемое randomList.whnf printElements - это функция a -> IO b, с которой мы связываемся.Результатом является новое значение IO, которое принимает первое значение IO, извлекает упакованное значение, применяет данную функцию и возвращает результат.

Другими словами, сама монада IOзаботится о том, чтобы отделить результат от randomList и применить к нему свою функцию, а не делать это явно.


(Вы могли заметить, что я сказал, что >>= связываетзначение для функции и наоборот. Возможно, точнее будет сказать, что >>= связывает их вместе в одно IO действие.)

...