Я играл со случайной функцией, которая дает бесконечный список случайных значений, как показано в главе 9 «Узнайте, что вам Haskell для Великого добра». Код выглядит следующим образом:Ошибка Haskell: Не удалось вывести (Random a0), возникающий из
randoms' :: (RandomGen g, Random a) => g -> [a]
randoms' gen = let (value, newGen) = random gen
in value : randoms' newGen
Для записи случайных генераторов, я изменил randoms'
немного к следующему:
randoms'' :: (RandomGen g, Random a) => g -> [(a, g)]
randoms'' gen = let (value, newGen) = random gen
in (value, newGen) : randoms'' newGen
Он работает, как ожидалось.
Тогда я переделал его в стиле списка понимания:
randoms''' :: (RandomGen g, Random a) => g -> [(a, g)]
randoms''' gen = random gen : [random gen' | (_, gen') <- randoms''' gen]
На этот раз, компилятор выдает ошибку: Не удалось вывести (Random a0), вытекающее из использования «Randoms» «»» ...... Тип переменной 'a0' неоднозначен ...
Однако, если указать тип randoms'''
с конкретными типами, например,
randoms''' :: StdGen -> [(Int, StdGen)]
randoms''' gen = random gen : [random gen' | (_, gen') <- randoms''' gen]
он отлично работает и дает точно такой же результат, как randoms''
.
Интересно, почему вывод типа работает для randoms''
, но не для randoms'''
. Может ли кто-нибудь сказать мне, почему эти два не эквивалентны и как исправить код randoms'''
?
Кроме того, я экспериментировал с тест-код, имеющий подобную структуру:
generate :: (Integral a, RealFrac b) => a -> (b,a)
generate m = let x = 1.2^^m in (x, ceiling x)
foo :: (Integral g, RealFrac a) => g -> [(a,g)]
foo gen = let (value, newGen) = generate gen
in (value, newGen) : foo newGen
foo' :: (Integral g, RealFrac a) => g -> [(a, g)]
foo' gen = generate gen : [generate gen' | (_, gen') <- foo' gen]
foo'' :: (Integral g, RealFrac a) => g -> [(a, g)]
foo'' gen = [generate gen' | gen' <- gen : map snd (foo'' gen)]
Оказывается, foo
foo'
и foo''
все работают отлично. По-видимому, это не проблема мономорфизма и полиморфизма. Кажется, это проблема, характерная для random
.
Вы отбрасываете фактическое значение, генерируемое 'randoms '' '' ('(_, gen') <- ...'), поэтому компилятор не имеет представления о том, какой тип создает экземпляр использования 'randoms ' «'; нет никаких оснований для того, чтобы он выбирал тот же тип 'a', который является выходом, или каким-либо другим конкретным типом, поэтому он неоднозначен. В мономорфном случае невозможно создать экземпляр - естественно, он может выбрать только «Int» для рекурсивного случая. – user2407038