Declaración de instancia ilegal para la clase de tipo TF
Frecuentes
Visto 838 equipos
2
I am having a problem declaring an instance of the following typeclass. I tried to follow the advice in the error message from the ghci compiler but still cannot get the code to compile. Any help would be appreciated.
class TF p where
valid :: p -> Bool
lequiv :: p -> p -> Bool
instance TF Bool
where
valid = id
lequiv f g = f == g
instance TF p => TF (Bool -> p)
where
valid f = valid (f True) && valid (f False)
lequiv f g = (f True) `lequiv` (g True)
&& (f False) `lequiv` (g False)
El error que recibo es:
Illegal instance declaration for ‘TF (Bool -> p)’
(All instance types must be of the form (T a1 ... an)
where a1 ... an are *distinct type variables*,
and each type variable appears at most once in the instance head.
Use FlexibleInstances if you want to disable this.)
In the instance declaration for ‘TF (Bool -> p)’
1 Respuestas
5
The problem here is that you have a type constructor (->
) applied to things that aren't type variables. There's a lot of ways you can deal with that:
FlexibleInstances
. This relaxes the assumption (made in the early days of Haskell, when it wasn't yet clear how difficult implementing type classes would be). This is not very controversial at all. On the other hand, it doesn't play that well with type inference: your instance will only be chosen when we sabes qué that we're supplying something of the shapeBool -> p
-- and in particular something that's polymorphic in the first argument will not match that shape. Sovalid id
will not typecheck without further annotations.TypeFamilies
. This gives us (among other things) access to a constraint which demands that two particular types be equal. So with this extension, you could writeinstance (bool ~ Bool, TF p) => TF (bool -> p) where ...
Now this matches whenever the thing we're supplying has shape
bool -> p
-- that is, any function at all -- and only after we have selected this instance does it check (in fact, enforce) that the argument type isBool
. Esto significavalid id
will typecheck; on the other hand, it also means you cannot declare instances for any other argument types.Add a typeclass. In fact, the only thing you really care about is that you can list all the inhabitants of
Bool
in not too much time. So you could instead declare a typeclass, say,Finite
, which you will instantiate at such types, and use it as the constraint on the argument type. Thus:instance (Finite arg, TF p) => TF (arg -> p) where valid f = all (valid . f) universe lequiv f g = all (\x -> f x `lequiv` g x) universe -- could also spell that lambda "liftA2 lequiv f g"
Then you would want to provide a
Finite
instancia paraBool
(which, luckily, is already available for you in theuniverse
package). This is nice because it combines the strengths of the previous two approaches: this instance will be chosen as soon as we know the argument is a function, and you can declare instances for many argument types by addingFinite
instances for them.
contestado el 28 de mayo de 14 a las 14:05
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas haskell or haz tu propia pregunta.
As the error message suggests, use
FlexibleInstaces
. To do that just put{-# LANGUAGE FlexibleInstances #-}
en la parte superior de su archivo fuente. - fizrukIf I didn't want to disable this feature, what would I need to change in the instance declaration to comply with the Haskell specification? - user3248346
Again, as error message tells you,
instance types must be of the form (T a1 ... an)
. In your case type isBool -> p
. aquí->
is type constructor and corresponds toT
mientrasBool
yp
corresponde aa1
ya2
. Es decirBool -> p
Se puede escribir como(->) Bool p
. El problema aquí es queBool
is concrete type, but withoutFlexibleInstances
it has to be type variable. So if you could make instance fora -> p
instead that would work. - fizrukPlease note that you are not disabling a feature, but rather disabling a restriction. So, requiring FlexibleInstances actually asks GHC to enable a new feature, allowing more general instances. - chi
FlexibleInstances
is one of the "very much ok" extensions. The restriction it removes is basically just there to make it easier to write a Haskell98 compiler, but from the user's point of view it's really more an arbitrary hindrance. - leftaroundabout