/ / Защо не мога да съответствам на модел на семейство тип? - хъски, типове

Защо не мога да сравнявам модел с типа семейство? - хъски, типове

Помислете за следния код:

{-# 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 е зависимият количествен показател, което показва, че аргументът на скрития тип не се изтрива, а по-скоро преминава и съответства на времето на изпълнение. Този ден все още не е дошъл, но мисля, че ще бъде.