Неопределенная переменная типа в поливариадном определении карри
Итак, я пытаюсь реализовать поливариадный ZipWithN, как описано здесь. К сожалению, код Paczesiowa, похоже, был скомпилирован с устаревшими версиями как ghc, так и HList, поэтому, пытаясь понять, как он работает, я также портировал его до самых последних версий обоих (ghc-7.8.3 и HList-0.3.4.1 в настоящее время). Это было весело.
В любом случае, я столкнулся с ошибкой, которую Google не помогает мне исправить на этот раз в определении посреднической функции. curryN'
, По идее, curryN'
прост: он принимает натуральное число на уровне типа N
(или, строго говоря, значение этого типа), и функция f
чей первый аргумент является HList длины N
и возвращает N
-Внутри функция, которая делает HList из своего первого N
аргументы и возвращает f
применяется к этому HList. Это curry
, но поливариадный.
Он использует три вспомогательные функции / классы:
Первый ResultType
/resultType
, как я определил здесь. resultType
принимает одну функцию в качестве аргумента и возвращает тип этой функции после применения ее к столько аргументов, сколько потребуется. (Строго говоря, опять же, он возвращает неопределенное значение этого типа).
Например:
ghci> :t resultType (++)
resultType (++) :: [a]
ghci> :t resultType negate
resultType negate :: (ResultType a result, Num a) => result
(Последний случай, потому что если a
случается, функция типа x -> y
, resultType должен был бы вернуть y
, Так что это не идеально применимо к полиморфным функциям.)
Вторые два Eat
/eat
а также MComp
/mcomp
определяется вместе (вместе с curryN'
) в одном файле (вместе со сломанным curryN'
) вот так.
eat
первый аргумент - это значение, тип которого является натуральным числом N
и возвращает функцию, которая принимает N
аргументы и возвращает их объединенные в HList:
ghci> :t eat (hSucc (hSucc hZero))
eat (hSucc (hSucc hZero)) :: x -> x1 -> HList '[x, x1]
ghci> eat (hSucc (hSucc hZero)) 5 "2"
H[5, "2"]
Насколько я могу сказать, это работает отлично. mcomp
является поливариадной составной функцией. Требуется две функции, f
а также g
, где f
принимает некоторое количество аргументов N
, Возвращает функцию, которая принимает N
аргументы, применяется f
ко всем из них, а затем относится g
в f
, (Функция порядка параллелей (>>>)
больше, чем (.)
)
ghci> :t (,,) `mcomp` show
(,,) `mcomp` show :: (Show c, Show b, Show a) => a -> b -> c -> [Char]
ghci> ((,,) `mcomp` show) 4 "str" 'c'
"(4,\"str\",'c')"
подобно resultType
, он "ломается" на функциях, чьи возвращаемые типы являются переменными типа, но так как я планирую использовать его только на eat
(чей конечный тип возврата просто HList
), это должно работать (Пацезова, кажется, так считает, по крайней мере). И это так, если первый аргумент eat
фиксированный:
\f -> eat (hSucc (hSucc hZero)) `mcomp` f
работает отлично.
curryN'
однако определяется так:
curryN' n f = eat n `mcomp` f
Попытка загрузить это в ghci, однако, получает эту ошибку:
Part3.hs:51:1:
Could not deduce (Eat n '[] f0)
arising from the ambiguity check for ‘curryN'’
from the context (Eat n '[] f,
MComp f cp d result,
ResultType f cp)
bound by the inferred type for ‘curryN'’:
(Eat n '[] f, MComp f cp d result, ResultType f cp) =>
Proxy n -> (cp -> d) -> result
at Part3.hs:51:1-29
The type variable ‘f0’ is ambiguous
When checking that ‘curryN'’
has the inferred type ‘forall f cp d result (n :: HNat).
(Eat n '[] f, MComp f cp d result, ResultType f cp) =>
Proxy n -> (cp -> d) -> result’
Probable cause: the inferred type is ambiguous
Failed, modules loaded: Part1.
Так ясно eat
а также mcomp
не играйте так хорошо, как хотелось бы. Между прочим, это значительно отличается от вида ошибки, которая mcomp (+) (+1)
т, который жалуется на перекрывающиеся экземпляры для MComp
,
В любом случае, попытка найти информацию об этой ошибке не привела меня к чему-то полезному - самым большим препятствием для моей собственной отладки было то, что я понятия не имел, что такое переменная типа. f0
даже, так как он не появляется ни в одной из сигнатур типов или контекстов, которые делает ghci.
Я думаю, что mcomp
возникают проблемы с повторением eat
полиморфный тип возвращаемого значения (даже несмотря на то, что это зафиксировано натуральным числом на уровне типа). Но если это так, я не знаю, как бы я это исправить.
Дополнительно (и странно для меня), если я пытаюсь объединить Part1.hs
а также Part2.hs
в один файл, я все еще получаю ошибку... но другой
Part3alt.hs:59:12:
Overlapping instances for ResultType f0 cp
arising from the ambiguity check for ‘curryN'’
Matching givens (or their superclasses):
(ResultType f cp)
bound by the type signature for
curryN' :: (MComp f cp d result, Eat n '[] f, ResultType f cp) =>
Proxy n -> (cp -> d) -> result
at Part3alt.hs:(59,12)-(60,41)
Matching instances:
instance result ~ x => ResultType x result
-- Defined at Part3alt.hs:19:10
instance ResultType y result => ResultType (x -> y) result
-- Defined at Part3alt.hs:22:10
(The choice depends on the instantiation of ‘cp, f0’)
In the ambiguity check for:
forall (n :: HNat) cp d result f.
(MComp f cp d result, Eat n '[] f, ResultType f cp) =>
Proxy n -> (cp -> d) -> result
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the type signature for ‘curryN'’:
curryN' :: (MComp f cp d result, Eat n [] f, ResultType f cp) =>
Proxy n -> (cp -> d) -> result
Failed, modules loaded: none.
Опять с загадочным f0
переменная типа Я признаю, что я немного над головой здесь со всей этой хакерской атакой, так что если кто-то может помочь мне выяснить, в чем именно заключается проблема, и, что более важно, как я могу ее исправить (если это так, надеюсь, возможно), я был бы невероятно благодарен.
Последнее замечание: причина того, что два файла здесь называются Part1 и Part3, состоит в том, что Part2 содержит некоторые вспомогательные функции, используемые в zipWithN
, но нет curryN'
, По большей части они работают нормально, но есть пара странностей, о которых я мог бы спросить позже.