Подтвердить что ты не робот

Ошибка типа с типом ранга-2 и составной функцией

Вот некоторые прагмы и некоторые импорты:

{-# LANGUAGE ScopedTypeVariables #-}

import Control.Monad.ST
import Data.Array.ST
import Data.Array

Теперь вот моя проблема. Следующие коды typechecks:

foo :: forall a. a -> [a]
foo x = elems $ runSTArray $ do
    newListArray (1,10) (replicate 10 x) :: ST s (STArray s Int a)

Однако, когда я заменяю $ на состав:

foo :: forall a. a -> [a]
foo x = elems . runSTArray $ do
    newListArray (1,10) (replicate 10 x) :: ST s (STArray s Int a)

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

Couldn't match expected type `forall s. ST s (STArray s i0 e0)'
            with actual type `ST s0 (STArray s0 Int a)'
In the expression:
    newListArray (1, 10) (replicate 10 x) :: ST s (STArray s Int a)
In the second argument of `($)', namely
  `do { newListArray (1, 10) (replicate 10 x) ::
          ST s (STArray s Int a) }'
In the expression:
      elems . runSTArray
  $ do { newListArray (1, 10) (replicate 10 x) ::
           ST s (STArray s Int a) }

Что ж, если я дам композиции функции своему собственному имени, то она снова проверяется:

elemSTArray = elems . runSTArray

foo :: forall a. a -> [a]
foo x = elemSTArray $ do
    newListArray (1,10) (replicate 10 x) :: ST s (STArray s Int a)

Я не уверен, что происходит здесь. Я бы ожидал, что вторая часть кода будет хорошо видна. И я не понимаю, почему это typechecks снова, если я даю скомпилированной функции свое собственное имя.

Это упрощенная версия некоторого кода, который у меня был сломан при обновлении с GHC 6.2 до 7, и я пытаюсь понять, почему это происходит сейчас. Спасибо за помощь!

4b9b3361

Ответ 1

Как вы уже намекаете в заголовке своего сообщения, проблема связана с runSTArray с полиморфным типом ранга 2.

runSTArray :: Ix i => (forall s. ST s (STArray s i e)) -> Array i e

С

elems :: Ix i => Array i e -> [e]

и

($) :: (a -> b) -> a -> b

запись runSTArray $ ... означает, что переменная типа a в схеме типа ($) должна быть создана с использованием полиморфного типа, а не мономорфного типа. Для этого требуется так называемый импрессивный полиморфизм. Как GHC реализует непроизводительный полиморфизм, объясняется в документе ICFP 2008 Димитриосом Витиниотисом, Стефани Вейрих и Саймоном Пейтоном Джонсом: FPH: первоклассный полиморфизм для Haskell. Суть в том, что, хотя FPH часто дает вам поведение, которое вы ожидаете, печатаемость иногда не сохраняется при простых преобразованиях, подобных тем, которые вы описываете в своем вопросе: см. Раздел 6.2 вышеупомянутой статьи.

Ответ 2

Стефан победил меня до ответа - сложный бит в том, что это не $ vs . между elems и runSTArray, что проблема - это $ после runSTArray. Поскольку something $ rankNthing настолько распространен, есть умный бит (я забыл детали), который пытается позволить вам сделать это как угловой случай. Но как-то использование композиции ранее предотвращает это. Местоположение проблемы демонстрируется тем фактом, что следующее будет выглядеть следующим образом:

foo x = (elems . runSTArray) (
    (newListArray (1,10) (replicate 10 x) :: ST s (STArray s Int String)))

Я не уверен, что это ошибка сама по себе, но это, безусловно, неожиданное поведение, заслуживающее того, чтобы создать билет, так как может быть лучший алгоритм для обнаружения таких случаев, как тот, который вы предоставили.