Jak mohu odvodit typeclass instance z omezení rodin, které jsou v působnosti?

0

Otázka

edit: jsem navázala s více konkrétní otázku. Děkuji answerers tady, a myslím, že navazující otázka se lépe vysvětluje některé nejasnosti jsem zde představil.


TL;DR jsem se snaží dostat dokladů o omezení do výrazů, při použití GADTs s existenciální omezení na konstruktérů. (to je vážně sousto, omlouvám se!)


Vytáhnul jsem problém až do následující. Mám jednoduchý GADT, které představuje body, tzv. X a funkce aplikací tzv. F. Body X jsou omezena tak, aby byla Objects.

data GADT ix a where
  X :: Object ix a => a -> GADT ix a
  F :: (a -> b) -> GADT ix a -> GADT ix b

Constrained odkazuje na nádoby, jejichž objekty jsou omezeny něco a Object je to něco. (edit: můj problém spočívá Category a Cartesian třídy z omezených-kategorie)

-- | I can constrain the values within containers of kind `* -> *`
class Constrained (ix :: * -> *) where
  type Object ix a :: Constraint

-- | Here's a trivial constraint. A more interesting one might include `Typeable a`, for ex
instance Constrained (GADT ix) where
  type Object (GADT ix) a = (Constrained ix, Object ix a)

Chtěl bych napsat vyjádření:

-- error: Could not deduce: Object ix Int arising from a use of ‘X’
ex0 :: GADT ix String
ex0 = F show (X (3 :: Int))

A zatímco jasné řešení funguje, to se rychle stává verbose při budování větších výrazy:

-- Typechecks, but eventually verbose
ex1 :: Object ix Int => GADT ix String
ex1 = F show (X (3 :: Int))

Myslím, že správné řešení by měl vypadat nějak takto:

-- error: Could not deduce: Object ix Int arising from a use of ‘X’
ex2 :: Constrained ix => GADT ix String
ex2 = F show (X (3 :: Int))

Ale já stále nemůže dostat, že důkaz Object ix Int.

Jsem si jistý, že je to jednodušší, než jsem myslel. Snažil jsem se přidávat omezení na Object omezení rodiny v GADT instanci třídy. Snažil jsem se nabízet omezení ve výrazu podpis. Snažil jsem se QuantifiedConstraints, i když, nejsem si jistý, že jsem plně pochopit. Prosím, pomozte mi, moudří!


Runnable:

{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE InstanceSigs #-}

module Test where

import Data.Kind
import Data.Functor.Identity
import Data.Functor.Const

-- | I can constrain the values within containers of kind `* -> *`
class Constrained (ix :: * -> *) where
  type Object ix a :: Constraint

-- | Here's a trivial constraint. A more interesting one might include `Typeable a`, for instance
instance Constrained (GADT ix) where
  type Object (GADT ix) a = (Constrained ix, Object ix a)

-- | A demo GADT that has function application ('F'), and points ('X'). The
-- points are constrained.
data GADT ix a where
  X :: Object ix a => a -> GADT ix a
  F :: (a -> b) -> GADT ix a -> GADT ix b

-- -- Broken
-- -- error: Could not deduce: Object ix Int arising from a use of ‘X’
-- ex0 :: GADT ix String
-- ex0 = F show (X (3 :: Int))

-- Typechecks
-- but for larger programs becomes verbose, requiring many explicit constraints
ex1 :: Object ix Int => GADT ix String
ex1 = F show (X (3 :: Int))

-- -- What I want, but, it's broken
-- ex2 :: Constrained ix => GADT ix String
-- ex2 = F show (X (3 :: Int))
2

Nejlepší odpověď

1

Bez kontextu těžko říct, co je nejlepší řešení, ale tady je pár možností:

Vyhnout se omezení na všechny

Jak to stojí, své GADT jak se zdá, nemá moc důvod pro omezení X k Object. Možná je to prostě není potřeba?

data GADT ix a where
  X :: a -> GADT ix a
  F :: (a -> b) -> GADT ix a -> GADT ix b

Místo toho omezení by mohlo přijít z venku , když je to potřeba.

Zatnout zuby omezení, seznamy, ale aby byly hezčí

Pokud máte mnoho různých typů ve vašem vyjádření, že vše je třeba splnit stejné omezení, můžete použít pomocníka, jako All

ex2' :: All (Object ix) '[Int] => GADT ix String
ex2' = F show (X (3 :: Int))

kde tam může být více typů v seznamu kromě Int; a/nebo si můžete vytvořit synonymum omezení, jako jsou

type StdObjs ix = (Object ix Int, Object x Bool, ...)

ex2'' :: StdObjs ix => GADT ix String
ex2'' = F show (X (3 :: Int))

Propagovat omezení dozadu přes datovou strukturu sám

Potřebujete-li omezení na X hodnoty, může však být možné vyjádřit jiným způsobem v GADT. Například, je-li tato funkce není obecné funkce, ale něco, co je již omezena pouze přijmout Objects, mohl jsi to takhle:

data YourFunc ix a b where
  YourFunc :: Object ix a => (a->b) -> YourFunc ix a b

show' :: Object ix Int => YourFunc ix Int String
show' = YourFunc show

To nemusí přímo pomoci s problémem, který jste se ptal, ale možná funkce je společná, nebo tak něco. Dalo by se dokonce mít něco jako

class Object ix a => InferrenceChain ix a where
  type PreElem ix a :: Type
  propInferrence :: (InferrenceChain ix (PreElem a) => r) -> r

a pak

data YourFunc ix a b where
  YourFunc :: InferrenceChain ix a
                 => (PreElem a -> a) -> YourFunc (PreElem a) a

Pak na konci mohli jste důkaz X omezení jen z uvedení v Object ix String na vnější straně a procházení přes propInferrence. Ale to by mě asi dost nešikovný.

2021-11-23 18:30:17

Zeptal jsem se na navazující otázku. Wrt eliding omezení, sledování ukazuje, proč je potřebuji. Wrt omezení seznamu, pořád si myslím, že často používaný by se stal nesnesitelně velké. Wrt YourFuncto by představit spoustu vpředu kotle plate (nový předehra), i když, pravděpodobně eliminovat budoucí smlouva. Wrt InferrenceChain,, Snažím se o mapu na můj problém, ale možná v návaznosti pomáhá vysvětlit lépe? Děkuji btw!
Josh.F

woh, jen jsem si uvědomil, že jsi autorem knihovny jsem si pohráváte s, constrained-categoriesdíky za knihovnu, je to úžasné!
Josh.F

No, jsem rád, že jste najít to užitečný!
leftaroundabout
1

Myslím, že správné řešení by měl vypadat nějak takto:

-- error: Could not deduce: Object ix Int >arising from a use of ‘X’
ex2 :: Constrained ix => GADT ix String
ex2 = F show (X 3)

Bohužel, toto řešení nedává smysl. Kompilátor je odůvodněno poukazem na to, že to neví, že Object ix Int je spokojený v tomto bodě, protože všichni to ví, je, že Constrained ix může uložit některá omezení prostřednictvím Object ix Int.

Řešení prostřednictvím kvantifikace

Takže možná to, co chcete, je omezení, které říká, že: "v tomto bodě, všechny Object ix a omezení použití jsou spokojeni," - kterou se můžeme snažit a dělat to přes kvantifikace:

{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ConstraintKinds #-}

type Satisfied ix = forall a. Object ix a

ex2 :: Satisfied ix => GADT ix String
ex2 = F show (X 3)

Bohužel, to nám dává GHC chyba:

• Quantified predicate must have a class or type variable head:
        forall a. Object ix a
• In the quantified constraint ‘forall a. Object ix a’
  In the type synonym declaration for ‘Satisfied’

Od Object je typ rodiny, a ne třídní nebo typové proměnné.

Re-architektura

Ale... proč je Object typ rodiny? Ve skutečnosti, proč Constrained existují vůbec jako nezákonný třídy bez metod? Pokud chceme uplatnit omezení na kombinace nádob a typy, Haskell již nám dává prostředky, jak to udělat - stačí použít například omezení!

{-# LANGUAGE MultiParamTypeClasses #-}

class Object ix a

type Constrained ix = forall a. Object ix a

Protože pokud máme

instance (...<some stuff>...) => Constrained Foo where
  type Object ix a = (...<some def>...)

mohli bychom to přeložit na

instance (...<some stuff>..., ...<some def>...) 
  => Object ix a

Což činí tento příklad zkompilovat.

ex2 :: Constrained ix => GADT ix String
ex2 :: F show (X 3)
2021-11-23 10:52:50

To dává smysl. Bohužel, co jsem zjednodušeny na Constrainedpodle mého skutečný problém, je ve skutečnosti Category a Cartesian z cartesian-categories, která jsou v souladu s metod. Neznám způsob, jiné než TypeFamilies (tj. omezení rodiny, zde) vyjádřit myšlenku třídy, jejichž objekty jsou libovolně omezena podtypy Hask, takže nemyslím si, že rearchitecture bude pracovat pro tento konkrétní problém.
Josh.F

Myslíš categories knihovny? Myslím, že budete muset poskytnout více motivující příklad, proč léčení Object jako třída nefunguje jako přístup, protože není mi jasné z pohledu na tyto třídy.
Isaac van Bakel

střílet, tak se omlouvám, že je to člověk! hackage.haskell.org/package/constrained-categories-0.4.1.0
Josh.F

ve skutečnosti, zde je přímý odkaz na třídu: hackage.haskell.org/package/constrained-categories-0.4.1.0/docs/...
Josh.F

Vaše příklady moc jít dolů stejnou cesty jsem šel pěšky. Wrt tvůj nápad rearchitecture to, zeptal jsem se na navazující otázku, která ukazuje, proč nemůžu, a sice, Object je typefamily, která omezuje co/domény a je požadavek z jiné knihovny.
Josh.F

V jiných jazycích

Tato stránka je v jiných jazycích

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................