Ось сценарій: я написав код з підписом типу, і GHC скарги не змогли вивести x ~ y для деяких x
і y
. Зазвичай можна закинути GHC кісткою і просто додати ізоморфізм до обмежень функції, але це погана ідея з кількох причин:
- Це не підкреслює розуміння коду.
- Ви можете закінчити 5 обмежень, де одного було б достатньо (наприклад, якщо 5 мають на увазі ще одне певне обмеження)
- Ви можете вирішити помилкові обмеження, якщо ви зробили щось не так або якщо GHC не допомагає
Я щойно провів кілька годин, бореться з випадком 3. Я граю syntactic-2.0
, і я намагався визначити незалежну від домену версію share
, схожу на версію, визначену в NanoFeldspar.hs
.
У мене було таке:
{-# LANGUAGE GADTs, FlexibleContexts, TypeOperators #-}
import Data.Syntactic
-- Based on NanoFeldspar.hs
data Let a where
Let :: Let (a :-> (a -> b) :-> Full b)
share :: (Let :<: sup,
Domain a ~ sup,
Domain b ~ sup,
SyntacticN (a -> (a -> b) -> b) fi)
=> a -> (a -> b) -> a
share = sugarSym Let
і GHC could not deduce (Internal a) ~ (Internal b)
, що, звичайно, не те, за що я йшов. Отже, або я написав якийсь код, який я не мав наміру (який вимагав обмеження), або GHC хотів, щоб це обмеження було обумовлене деякими іншими обмеженнями.
Виявляється, мені потрібно було додати (Syntactic a, Syntactic b, Syntactic (a->b))
список обмежень, жоден з яких не означає (Internal a) ~ (Internal b)
. Я в основному натрапив на правильні обмеження; У мене ще немає систематичного способу їх пошуку.
Мої запитання:
- Чому GHC запропонував це обмеження? Ніде в синтаксиці немає обмежень
Internal a ~ Internal b
, тож звідки GHC це взяв? - Загалом, які методи можна використовувати для відстеження походження обмеження, яке, як вважає GHC, потребує? Навіть щодо обмежень, які я можу виявити сам, мій підхід, по суті, є грубим змушенням порушника шляхом фізичного записування рекурсивних обмежень. Такий підхід в основному знижує нескінченну кролячу діру обмежень і є приблизно найменш ефективним методом, який я можу собі уявити.
a
і b
пов'язане - подивіться на підпис типу поза вашим контекстом - a -> (a -> b) -> a
, ні a -> (a -> b) -> b
. Може, це все? За допомогою вирішувачів обмежень вони можуть впливати на перехідну рівність де завгодно , однак помилки зазвичай показують місце "близько" до місця, де викликано обмеження. Це було б круто, але @jozefg - можливо, коментуючи обмеження тегами чи щось таке, щоб показати, звідки вони взялися? : s