Почему я не могу вызвать функцию быстрой сортировки (randomList 10)?

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

import Data.Array
import Control.Monad
import Data.Functor 
import System.Random (randomRIO)

randomList 0 = return []
randomList n = do
  r  <- randomRIO (1,6)
  rs <- randomList (n-1)
  return (r:rs) 

quicksort [] = []  
quicksort (x:xs) =   
    let smallerSorted = quicksort [a | a <- xs, a <= x]  
        biggerSorted = quicksort [a | a <- xs, a > x]  
    in  smallerSorted ++ [x] ++ biggerSorted  
  1. randomList — создает список заданной длины и заполняет его случайными значениями;
  2. quicksort — быстро сортирует список.

Мне нужно применить сортировку к созданному массиву: quicksort (randomList 10), но возникает ошибка:

"Couldn't match expected type‘ [a] ’with actual type IO [Int]’"

person Vasiliy    schedule 20.04.2019    source источник
comment
Вы должны fmap quicksort (randomList 10).   -  person Willem Van Onsem    schedule 20.04.2019
comment
вы должны включить сигнатуры типов для всех имен верхнего уровня в вашей программе. если вы их не знаете, загрузите файл и спросите GHCi: Main> :t randomList. Затем скопируйте и вставьте его в файл (или сначала настройте его по своему усмотрению). Поместите сигнатуру типа над именем, которое она описывает.   -  person Will Ness    schedule 20.04.2019
comment
@WillemVanOnsem, да, отлично, так оно и работает.   -  person Vasiliy    schedule 20.04.2019


Ответы (1)


Вы должны включить сигнатуры типов для всех имен верхнего уровня в вашей программе. если вы их не знаете, загрузите файл и спросите GHCi: Main> :t randomList. Затем скопируйте и вставьте его в файл (или сначала настройте его по своему усмотрению). Поместите сигнатуру типа над именем, которое она описывает.

GHCI говорит

randomList ::
  (System.Random.Random t, Num t, Num a, Eq a) => a -> IO [t]

но вы, скорее всего, имели в виду

randomList :: (System.Random.Random t, Num t) => Int -> IO [t]
randomList 0 = return []
randomList n = do
  r  <- randomRIO (1,6)    -- randomRIO (1,6) :: IO t  , r :: t
  rs <- randomList (n-1)   --             rs :: [t]
  return (r:rs)            --    r :: t , rs :: [t] 

В целом,

randomRIO (1,6) :: (System.Random.Random a, Num a) => IO a

Вы бросаете шестигранный кубик n раз и записываете результаты в список. Кстати то же самое делает

sequence $ replicate n (randomRIO (1,6))
===
replicateM n (randomRIO (1,6))

> :t \n -> replicateM n (randomRIO (1,6))
           :: (System.Random.Random a, Num a) => Int -> IO [a]

Затем GHCi также сообщает нам, что

 quicksort :: Ord t => [t] -> [t]

Но randomList n это IO [t], а не [t]. Чтобы получить значение [t] внутри IO [t], вам нужно сделать это внутри:

sortRandom :: (Ord t, Monad m) => m [t] -> m [t]
sortRandom randomlist = do
    xs <- randomlist        -- randomlist :: IO [t] , xs :: [t]
    let ys = quicksort xs
    return ys

Вышесказанное можно сократить до

sortRandom :: (Ord t, Monad m) => m [t] -> m [t]
sortRandom = liftM quicksort     -- for monads

or

sortRandom :: (Ord t, Functor f) => f [t] -> f [t]
sortRandom = fmap quicksort      -- for functors

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

foo :: Int -> IO [Int]
foo n = liftM quicksort $ replicateM n (randomRIO (1,6))
person Will Ness    schedule 20.04.2019
comment
При компиляции получаю ошибку в этой строке: randomList::(System.Random.Random t, Num t) =› Int -> IO[t] Not in scope: type конструктор или класс ‘System.Random.Random’ - person Vasiliy; 20.04.2019
comment
сделать import System целиком, без (randomRIO). - person Will Ness; 20.04.2019
comment
Могу ли я после этого сделать следующее? sort n = do list <- randomList n let res = sortRandom list return res - person Vasiliy; 20.04.2019
comment
нет. следите за типами! (это общий лозунг Haskell). идите по очереди, медленно, записывайте типы: randomList n :: IO [Int]; следовательно, list :: [Int]; sortRandom :: (Monad m) => m [Int] -> m [Int] или специально для IO, sortRandom :: IO [Int] -> IO [Int]. это означает, что эта функция ожидает IO [Int], а не только [Int]. Так что list :: [Int] не может быть его аргументом. но у нас есть quicksort, который может принимать аргумент [Int], поэтому для let res = quicksort list, res :: [Int]. и так return res :: IO [Int]. Скоро поищу ссылку на объяснение do... - person Will Ness; 20.04.2019
comment
@ Василий, если вы работаете в IO и со случайностью, вам действительно следует использовать настоящую быструю сортировку вместо этой поддельной! Единственная сложность в том, что вам придется переключаться со списков на массивы. Конечно, если вы не приверженец быстрой сортировки, вам почти наверняка следует вместо этого использовать другой алгоритм: восходящая сортировка слиянием очень удобна в Haskell, и пирамидальная сортировка тоже подойдет. - person dfeuer; 20.04.2019
comment
@WillNess, Пока нет четкого понимания как это работает. Но ты мне здорово помогаешь! Благодарю вас! - person Vasiliy; 20.04.2019
comment
@Vasiliy Я пытаюсь объяснить нотацию do здесь. также ознакомьтесь с другими моими ответами в do-notation. - person Will Ness; 21.04.2019
comment
@Vasiliy также, это. так что с нотацией do материал справа от <- живет в некоторой монаде M -- Это могут быть M a, M b и т. д., но с одним и тем же M для каждой строки в do. и если справа от <- есть значение типа M a, значение слева от него имеет тип a. это главное. кроме того, do могут свободно вкладываться и разбираться: `do { A ; Б; С } == сделать { А ; сделать {В; C}} == сделать { сделать { A; Б}; С}. если у вас есть вопрос, не стесняйтесь спрашивать. - person Will Ness; 21.04.2019