Проблема с вашим кодом находится в последней строке, та, что с аннотацией типа :: (Double, g)
.Как написано, вы явно ожидаете, что g
в этой аннотации будет ссылаться на тот же g
, что и в вашей подписи типа для simulator
.Это вполне разумное ожидание, но, к сожалению, это не так - по умолчанию две переменные типа с одним и тем же именем в разных типах аннотаций различны.(Вот почему в сообщении об ошибке GHC неявно переименовывает ваш второй g
в g1
.)
К счастью, вы можете это исправить.GHC поставляется с расширением языка, которое можно включить, и называется ScopedTypeVariables
.Если вы добавите {-# LANGUAGE ScopedTypeVariables #-}
в начало вашего модуля, это активирует расширение.Однако это все равно не исправит вашу программу, поскольку ScopedTypeVariables
применяется только к переменным , явно связанным с использованием forall
.Следовательно, вам нужно добавить LANGUAGE
pragma и для явного использования forall
:
{-# LANGUAGE ScopedTypeVariables #-}
import System.Random
simulator :: forall g. (RandomGen g) => g -> Double -> (Bool, g)
simulator gen p = (x <= p, gen2)
where (x, gen2) = random gen :: (Double, g)
Этих заклинаний достаточно, чтобы заставить GHC выполнить то, что вы изначально намеревались.
Тем не менее, ваша оригинальная программа на самом деле также будет компилироваться, если вы просто отбросите сигнатуру второго типа и оставите ScopedTypeVariables
отключенным, поскольку GHC выведет соответствующий тип для gen2
в зависимости от того, как он используется.Хотите ли вы подпись типа или нет, это личное предпочтение, но все же полезно понимать, что происходит и как это исправить, в ситуациях, когда вы решаете, что действительно хотите подпись, или где подпись действительно необходима.