Синоним шаблона связывается не так, как обычный шаблон

Функция f не проверяет тип в следующем коде, который использует синглтоны с Frames и Vinyl:

f :: forall rs1 rs2.  SList rs1 -> Frame (Record rs1) -> Int
f (OnlyRecord s1 t1) df1 = broadcast (*) (rhead <$> df1)

pattern OnlyRecord :: Sing s -> Sing t -> SList '[s :-> t]
pattern OnlyRecord sym typsing = SCons (SRecArrow sym typsing) SNil

rhead :: Record ((s :-> t) ': sstt) -> t
rhead (x :& xs) = getCol $ getIdentity x

data instance Sing (a :: Type) where
    SRecArrow :: Sing (s :: Symbol) -> Sing (t :: Type) -> Sing (s :-> t)

Ошибка Couldn't match type ‘rs1’ with ‘'[s2 :-> t1] в вызове rhead - в основном кажется, что сопоставление с образцом не связывает структуру rs1, как я ожидал. Но если я встраиваю шаблон, он проверяет:

f' :: forall rs1 rs2.  SList rs1 -> Frame (Record rs1) -> Int
f' (SCons (SRecArrow s1 t1) SNil) df1 = broadcast (*) (rhead <$> df1)

Учитывая, что синоним шаблона должен быть, ну, в общем, синонимом, не должен ли он работать идентично встроенному шаблону?

1 ответ

Решение

Определение синонима шаблона является правильным; это неправильный тип. Правильный тип

pattern OnlyRecord :: () => (rs ~ '[s :-> t]) => Sing s -> Sing t -> SList rs
pattern OnlyRecord ...

С вашей оригинальной подписью типа шаблона (что эквивалентно () => () => Sing s -> Sing t -> SList '[s :-> t]), вы утверждаете, что с учетом выражения x :: SList '[s :-> t] Вы можете сопоставить это выражение, используя свой синоним шаблона. Однако в f, у вас нет такого выражения - у вас есть только x :: SList rs1 для некоторых rs1, что является строго более общим. С правильной сигнатурой вы можете использовать синоним шаблона для сопоставления с таким выражением, поскольку синоним шаблона объявлен применимым к любому SList rs; а затем предоставленные ограничения (а именно rs ~ '[s :-> t]) доступны в рамках сопоставления с образцом.

Дополнительные сведения о сигнатурах шаблонов см. В руководстве пользователя GHC.

Другие вопросы по тегам