Бесполезная ошибка равенства рода в начале файла
я получаю сообщение об ошибке
app\Main.hs:1:1: error:
Couldn't match kind `*' with `Constraint'
When matching types
b :: *
(Set b, Set s) :: Constraint
|
1 | {-# LANGUAGE TypeFamilies #-}
| ^
я не знаю почему
b
и ограничение
(Set b, Set s)
сопоставляются? Я бы ожидал, что ограничение будет экзистенциально количественно определять тип b, но почему оно должно им соответствовать?
Я считаю, что последнее, что я изменил перед тем, как получить ошибку, — это добавить OpOutcome в класс.
вот код
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableSuperClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE RankNTypes #-}
module Main where
import GHC.TypeLits (Symbol)
import GHC.Exts (Constraint)
import Data.Reflection (Reifies, reflect)
import Data.Proxy (Proxy(..))
main :: IO ()
main = print 5
class ((a,b)::Constraint) => HasCtxt a b
instance (a,b) => HasCtxt a b
class Determines a b | a -> b
instance Determines a b => Determines a b
type Set b = (b ~ b)
type OpLayout a = (forall s ctxt b. (OpCtxt a s b ~ ctxt, Determines a b, Determines a ctxt,Reifies s b) => ( HasCtxt ctxt (Reifies s b))) :: Constraint
data Stack a where
Cons :: OpConstructor a -> Stack b -> Stack a
Nil :: Stack "NIL"
class OpLayout a => OpCode (a::Symbol) where
type OpCtxt a s b = (ctxt :: Constraint) | ctxt -> s b
type OpOutcome a :: *
data OpConstructor a
opValue :: Determines a s => Proxy s
opValue = Proxy
popOP :: OpCtxt a s b => Stack a -> (b :: *)
evalOP :: OpConstructor a -> Stack x -> OpOutcome a
instance OpCode "load_val" where
type OpCtxt "load_val" s b = (Set s, Set b)
type OpOutcome "load_val" = Stack "load_val"
data OpConstructor "load_val" = forall b. LOAD_VAL b
popOP stack = reflect opValue
evalOP op stack = op `Cons` stack
редактирование: уменьшенная версия, спасибо Кшиштофу Гоголевскому
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE PolyKinds #-}
module Err where
import GHC.Exts (Constraint)
class Determines b | -> b
class (forall (b :: *) (c :: Constraint). (Determines b, Determines c) => c) => OpCode
instance OpCode
1 ответ
Вот файл гораздо меньшего размера, в котором, по сути, та же ошибка:
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE FlexibleContexts #-}
module Test where
import GHC.Exts (Constraint)
class Determines a b | a -> b
class (forall ctxt. (Determines a a, Determines a (OpCtxt a)) => ctxt) => OpCode a where
type OpCtxt a :: Constraint
instance OpCode ()
Это дает:
test.hs:1:1: error:
Couldn't match kind ‘Constraint’ with ‘*’
When matching types
OpCtxt () :: Constraint
() :: *
|
1 | {-# LANGUAGE TypeFamilies #-}
| ^
(Кстати, в будущем вам, вероятно, стоит попробовать сделать подобную минимизацию самостоятельно, прежде чем спрашивать здесь.)
Это, безусловно, ошибка, что GHC сообщает об ошибке с такой бесполезной информацией о местоположении. Однако сейчас так мало мест, где может скрываться проблема, что мы можем иметь довольно хорошее представление о том, что происходит. Ситуация здесь такова, что мы просим
Determines a a
Determines a (OpCtxt a)
с функциональной зависимостью в области действия, которая говорит, что должно быть достаточно, чтобы обработать другой аргумент для
Determines
. Ну, мы знаем,
*
, потому что мы пишем
instance OpCode ()
а также
() :: *
; и мы знаем, имеет вид
Constraint
, потому что мы сказали это в объявлении класса. Поэтому GHC отказывается от попыток унифицировать и
OpCtxt a
еще до того, как это начнется - у них разные виды, поэтому они не могут быть равными!
Единственный трюк, который вам нужен, чтобы увидеть, почему вы получаете именно то сообщение об ошибке, которое вы делаете, это придерживаться
()
за
a
везде (потому что это экземпляр, который мы пытаемся написать).
Возвращаясь к вашей настройке: вы просите
Determines a b
Determines a ctxt
откуда мы знаем
b :: *
потому что он появляется как второй аргумент
Reifies :: k -> * -> Constraint
, и мы знаем
ctxt :: Constraint
потому что мы сказали так в
OpCode
объявление класса. Таким образом, функциональная зависимость не может работать правильно. Затем вы получите ошибку, которую видели, поставив
OpCtxt "load_val" s b
за
ctxt
, а затем сводится к
(Set s, Set b)
.