Я реализовал преобразователи в Haskell следующим образом:
{-# LANGUAGE RankNTypes #-}
import Prelude hiding (foldr)
import Data.Foldable
type Reducer b a = a -> b -> b
type Transducer a b = forall t. Reducer t b -> Reducer t a
class Foldable c => Collection c where
insert :: a -> c a -> c a
empty :: c a
reduce :: Collection c => Transducer a b -> c a -> c b
reduce f = foldr (f insert) empty
mapping :: (a -> b) -> Transducer a b
mapping f g x = g (f x)
Теперь я хочу определить общую функцию map
. Поэтому я загружаю приведенный выше код в GHCi:
Prelude> :load Transducer
[1 of 1] Compiling Main ( Transducer.hs, interpreted )
Ok, modules loaded: Main.
*Main> let map = reduce . mapping
<interactive>:3:20:
Couldn't match type ‘Reducer t0 b1 -> Reducer t0 a1’
with ‘forall t. Reducer t b -> Reducer t a’
Expected type: (a1 -> b1) -> Transducer a b
Actual type: (a1 -> b1) -> Reducer t0 b1 -> Reducer t0 a1
Relevant bindings include
map :: (a1 -> b1) -> c a -> c b (bound at <interactive>:3:5)
In the second argument of ‘(.)’, namely ‘mapping’
In the expression: reduce . mapping
*Main> let map f = reduce (mapping f)
*Main> :t map
map :: Collection c => (a -> b) -> c a -> c b
Поэтому я не могу определить map = reduce . mapping
. Однако я могу определить map f = reduce (mapping f)
.
Я считаю, что эта проблема вызвана ограничением мономорфизма. Мне бы очень хотелось написать map = reduce . mapping
вместо map f = reduce (mapping f)
. Отсюда у меня два вопроса:
- Что вызывает эту проблему? Действительно ли это ограничение мономорфизма?
- Как решить эту проблему?
let map :: Collection c => (a -> b) -> c a -> c b; map f = reduce (mapping f)
по-прежнему выдает ту же ошибку. - person Aadit M Shah   schedule 11.01.2015mapping
автоматически изменяется, чтобы переместитьforall
в левую часть (попробуйте:t mapping
). Это допустимое (сохраняющее семантику) преобразование, но средство проверки типов ожидает правильный типTransducer a b
, а неReducer t a -> Reducer t b
(которые могут быть разными типами). Но когда вы пишетеreduce (mapping f)
, программа проверки типов видит, что приложениеmapping f
должно иметь типforall t. Reducer t b -> Reducer t a
, который является правильным типом для аргументаreduce
. - person user2407038   schedule 11.01.2015let map = ((.) :: (Transducer a b -> c a -> c b) -> ((a -> b) -> Transducer a b) -> (a -> b) -> (c a -> c b)) reduce mapping
работает, но... фигня. Это(.)
, которому нужна аннотация. - person chi   schedule 11.01.2015data-fix
, который дает вам более общий случай, чем датчики, называемыеF-algebras
. Преобразователи по существу представляют собой F-алгебры, но только для спискообразных структур. - person Heimdell   schedule 11.01.2015f (x :: forall a. ...)
, аf
имеет полиморфный типb -> ...
, тоb
не преобразуется вforall a. ...
, поскольку переменные типа могут быть созданы только во время вывода монотипов. Что происходит, так это то, чтоa
получает новую константу skolema0
, а затемf
больше не получает полностью полиморфное значение. (По крайней мере, это то, что я понял — я определенно не эксперт в том, как именно GHC делает вывод) - person chi   schedule 11.01.2015reduce
объявлено как имеющее типT
, использованиеreduce :: T
вместо простоreduce
не сообщает GHC ничего, чего он еще не знает. Сигнатуры типов имеют значение, когда они сообщают GHC, как специализировать более общий тип: здесьreduce
иmapping
используются с их полной универсальностью, поэтому никакой специализации не требуется. Вместо этого(.)
является специализированным. - person chi   schedule 11.01.2015type
там не работает лучше: stackoverflow.com/a/27944035/ 1308058 - person phadej   schedule 14.01.2015