Как разрешить унификацию переменной типа с разными типами?

У меня есть функция со следующей подписью типа

{-# LANGUAGE FlexibleContexts #-}
dataLat :: Load r DIM1 Double
        => (Array r DIM1 Double -> Array U DIM1 Double, Array U DIM1 Double)

Array, U и DIM1 взяты из библиотеки Repa. dataLat создает данные, которые позже передаются другим функциям в виде кортежа. В какой-то момент переменная типа r унифицируется с типом D (это опять же от Repa), но позже r также должна унифицироваться с типом L (это мой тип). Проблема в том, что он уже унифицирован с D и поэтому не может быть унифицирован с L. Я получаю ошибку Couldn't match expected type. Я думаю, что это должно быть решено с помощью какой-либо формы типов более высокого ранга, но я не могу понять, как это должно быть написано. Может ли кто-нибудь дать мне руку?


person Jan Stolarek    schedule 27.11.2012    source источник


Ответы (2)


Try {-# LANGUAGE NoMonomorphismRestriction #-}

http://www.haskell.org/ghc/docs/7.6.1/html/users_guide/monomorphism.html

person Ben Lippmeier    schedule 27.11.2012
comment
Бинго! В какой-то момент мне пришло в голову, что это может быть вызвано мономорфизмом - я не знаю, почему я не проверил это. - person Jan Stolarek; 28.11.2012

Вы можете указать dataLat тип, говорящий, что он возвращает полиморфную функцию, используя Rank2Types.

newtype Unboxer =
  Unboxer {applyUnboxer :: forall repr. Load repr DIM1 Double => Array repr DIM1 Double -> Array U DIM1 Double}

dataLat :: (Unboxer, Array U DIM1 Double)

Тело dataLat должно поместить полиморфную функцию в Unboxer. Метод доступа к полю applyUnboxer возвращает полиморфную функцию, которую можно использовать для разных типов.

Мне не ясно, действительно ли вам нужны типы ранга 2. Поскольку dataLat не принимает аргументов, вы, вероятно, можете определить распаковщик как глобальную функцию с обычным полиморфизмом ранга 1.

Чтобы быть точным, нет смысла унифицировать переменную типа с несколькими типами. Объединить r с U и D означало бы сказать, что r == U и U == D, что неверно. Приведенный выше код позволяет создавать экземпляры функции для нескольких типов. Думайте о создании экземпляра как о создании копии кода перед назначением типов, чтобы у вас был один экземпляр функции, где r₁ == U, и отдельный экземпляр, где r₂ == D.

person Heatsink    schedule 27.11.2012
comment
Спасибо, Радиатор, но этот обходной путь заставил бы меня изменить код во многих местах. Ответ Бена правильный - проблема вызвана ограничением мономорфизма. - person Jan Stolarek; 28.11.2012