Ошибка переменной жесткого типа в Haskell - PullRequest
0 голосов
/ 24 июня 2018

Я новичок в Haskell. Я хотел бы знать, почему не работает следующее:

import System.Random

simulator :: (RandomGen g) => g -> Double -> (Bool, g)
simulator gen p = (x <= p, gen2)
    where (x, gen2) = random gen :: (Double, g)

Я получаю ошибку:

• Couldn't match type ‘g’ with ‘g1’
  ‘g’ is a rigid type variable bound by
    the type signature for:
      simulator :: forall g. RandomGen g => g -> Double -> (Bool, g)
    at simulate.hs:10:1-54
  ‘g1’ is a rigid type variable bound by
    an expression type signature:
      forall g1. (Double, g1)
    at simulate.hs:12:37-47
  Expected type: (Double, g1)
    Actual type: (Double, g)
• In the expression: random gen :: (Double, g)
  In a pattern binding: (x, gen2) = random gen :: (Double, g)
  In an equation for ‘simulator’:
      simulator gen p
        = (x <= p, gen2)
        where
            (x, gen2) = random gen :: (Double, g)
• Relevant bindings include
    gen :: g (bound at simulate.hs:11:11)
    simulator :: g -> Double -> (Bool, g) (bound at simulate.hs:11:1)

     where (x, gen2) = random gen :: (Double, g)

Похоже, Haskell не может сопоставить отдельные экземпляры переменной типа g. Любые подсказки?

1 Ответ

0 голосов
/ 24 июня 2018

Проблема с вашим кодом находится в последней строке, та, что с аннотацией типа :: (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 в зависимости от того, как он используется.Хотите ли вы подпись типа или нет, это личное предпочтение, но все же полезно понимать, что происходит и как это исправить, в ситуациях, когда вы решаете, что действительно хотите подпись, или где подпись действительно необходима.

...