Синоним шаблона связывается не так, как обычный шаблон
Функция 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.