/ / Чому я не можу відстежувати відповідність типу сім'ї? - haskell, типи

Чому я не можу зібрати зразок для сімейства типу? - haskell, типи

Розглянемо наступний код:

{-# LANGUAGE TypeFamilies #-}

data Twothings a b = Twothings a b

type family Leftthing a where
Leftthing (Twothings a b) = Leftthing a
Leftthing a = a

leftthing :: a -> Leftthing a
leftthing (Twothings a b) = leftthing a
leftthing b = b

Він не компілює з наступною помилкою:

Couldn"t match expected type ‘a’
with actual type ‘Twothings a0 t0’
‘a’ is a rigid type variable bound by
the type signature for:
leftthing :: forall a. a -> Leftthing a

Він скаржиться на лінію leftthing (Twothings a b) = leftthing a. Якщо я правильно розумію, це не може уніфікувати змінну типу a у тип підпису з типом конструктора Twothings. Гаразд, це, мабуть, має сенс. Але потім, Як я можу коли-небудь визначити функцію з типом сімей в тип підпису?

Відповіді:

11 за відповідь № 1

Коли ти оголошувати

leftthing :: a -> Leftthing a

ти кажеш, що абонент від leftthing отримує вибір що a є

Коли ти тоді напишеш

leftthing (Twothings a b) = leftthing a

ти є припускаючи що вони обрали а Twothings типу, і тому що це не обов'язково, ваша програма відхилена.

Ви, можливо, подумали, що ти був тестування чи вони вибрали а Twothings типу, але ні! Тип інформації стирається перед тим, як запускати час, тому неможливо провести такий тест.

ви може спробуйте відновити необхідну інформацію про час роботи. Спочатку дозвольте мені виправити невідповідність між вами Leftthing і leftthing.

type family Leftthing a where
Leftthing (Twothings a b) = Leftthing{-you forgot the recursion!-} a
Leftthing a = a

Тепер ми можемо визначити GADT свідків для TwothingНесс

data IsItTwothings :: * -> * where
YesItIs   :: IsItTwothings a -> IsItTwothings (Twothings a b)
NoItIsn"t :: Leftthing a ~ a => IsItTwothings a
-- ^^^^^^^^^^^^^^^ this constraint will hold for any type
-- which is *definitely not* a Twothings type

І тоді ми можемо передати свідчення як аргумент:

leftthing :: IsItTwothings a -> a -> Leftthing a
leftthing (YesItIs r) (Twothings a b) = leftthing r a
leftthing NoItIsn"t   b               = b

Насправді, свідок є універсальним кодуванням числа лівосховищ Twothingses в кореневій частині вашого типу. Цього достатньо інформації, щоб визначити під час виконання правильну кількість розпакування.

> leftthing (YesItIs (YesItIs NoItIsn"t)) (Twothings (Twothings True 11) (Twothings "strange" [42]))
True

Підводячи підсумок, ви не можете з'ясувати тип за шаблономвідповідність за значенням. Швидше за все, вам потрібно знати, який тип виконується для відповідності шаблону (оскільки тип визначає макет пам'яті, а теги типу часу виконання не існують). Ви не можете безпосередньо моделювати відповідність типів (тому що вони "просто не підходять"). Ви можете побудувати типи даних, які діють як дані про структуру типу типів часу і відповідають на них.

Можливо, одного дня ваша програма буде працювати, якщо ви надішлете йому тип

leftthing :: pi a. a -> Leftthing a

де pi є залежним квантором, що вказує на те, що аргумент прихованого типу не видаляється, а скоріше проходить і узгоджується під час виконання. Цей день ще не прийшов, але я думаю, що це буде.