"Kısıtlama numarası" neden bu manuel olarak tanımlanmış HasField örneğinde çalışmıyor?


9

Ben kullandığı bu (muhakkak garip) koduna sahip lens ve GHC.Records :

{-# LANGUAGE DataKinds, PolyKinds, FlexibleInstances, UndecidableInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
module Main where
import Control.Lens
import GHC.Records 

data Glass r = Glass -- just a dumb proxy

class Glassy r where
  the :: Glass r

instance Glassy x where
  the = Glass

instance (HasField k r v, x ~ r)
-- instance (HasField k r v, Glass x ~ Glass r) 
  => HasField k (Glass x) (ReifiedGetter r v) where
  getField _ = Getter (to (getField @k))

data Person = Person { name :: String, age :: Int } 

main :: IO ()
main = do
  putStrLn $ Person "foo" 0 ^. runGetter (getField @"name" the)

Fikir , sadece cehennem için bir HasFieldvekilden çağrışan bir örneğe sahip olmaktır ReifiedGetter. Ama işe yaramıyor:

* Ambiguous type variable `r0' arising from a use of `getField'
  prevents the constraint `(HasField
                              "name"
                              (Glass r0)
                              (ReifiedGetter Person [Char]))' from being solved.

Neden r0belirsiz kaldığını anlamıyorum . Kısıtlama hilesini kullandım ve sezgim, örnek başının eşleşmesi gerektiğinde, daktilocu r0 ~ Personön koşullarda bulacaktır ve bu belirsizliği kaldıracaktır.

Şunu değiştirirsem (HasField k r v, x ~ r)içine (HasField k r v, Glass x ~ Glass r)o uzaklaşmaların belirsizlik ve cezası derler. Ama neden çalışıyor ve neden başka şekilde çalışmıyor?

Yanıtlar:


9

Belki de şaşırtıcı bir şekilde, Glasspoli-nazik olmakla ilgisi vardı :

*Main> :kind! Glass
Glass :: k -> *

Bu arada, tür parametresinden farklı olarak Glass, "kayıt" HasFieldtüründe olmalıdır Type:

*Main> :set -XPolyKinds
*Main> import GHC.Records
*Main GHC.Records> :kind HasField
HasField :: k -> * -> * -> Constraint

Eğer böyle bağımsız bir imza eklerseniz:

{-# LANGUAGE StandaloneKindSignatures #-}
import Data.Kind (Type)
type Glass :: Type -> Type
data Glass r = Glass

sonra bile daktilo ile kontrol eder (HasField k r v, x ~ r).


Aslında, nazik imzayla, "kısıtlama hilesi" gerekli olmaktan çıkar:

instance HasField k r v => HasField k (Glass r) (ReifiedGetter r v) where
  getField _ = Getter (to (getField @k))

main :: IO ()
main = do
  print $ Person "foo" 0 ^. runGetter (getField @"name" the)
  print $ Person "foo" 0 ^. runGetter (getField @"age" the)

Burada, daktilo denetimi sırasında bilgi akışı şöyledir:

  • Biz bir var biliyorum Persondiye yoluyla, runGetteriçinde -the alanın türü HasFieldolmalıdır ReifiedGetter Person vve rolmalıdır Person.
  • Çünkü rolması Persongereken kaynak türü HasFieldolmalıdır Glass Person. Şimdi önemsiz Glassyörneğini çözebiliriz the.
  • Anahtar kiçinde HasFieldbir tür sabitin olarak verilir: Symbol name.
  • Örnek ön koşullarını kontrol ediyoruz. Biliyoruz kve fonksiyonel bağımlılık nedeniyle rortaklaşa karar veriyorlar . Örneği (Automagically kayıt türleri için oluşturulan) var ve şimdi bunu biliyoruz olduğunu . Tüm türleri başarıyla ortadan kaldırdık.vHasFieldvString
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.