(1+) `fmap` (2, 3)
. And after that, check the result obtained, for example, in ghci
. For many, did the result of a manual calculation coincide with the one that the system issued? And if your results still coincided, I would really like to hear a good explanation of how you did it.Incable
class of incremental types: class Incable t where inc :: t -> t
instance (Num t) => Incable t where inc = (1+)
UndecidableInstances
language, and then completely confuse the situation. Therefore, we confine ourselves to the definitions only for the most basic representatives of the class Num
- types Integer
and Double
. instance Incable Integer where inc = (1+) instance Incable Double where inc = (1+)
Incable
: instance (Functor f, Incable t) => Incable (ft) where inc = fmap inc
Maybe
structures and another set of types for which instances of the Functor
class are defined. Among all this diversity will be a pair of incremental values. However, suppose (even if we have found a convincing explanation for the current behavior of pairs as functors) that in our case it is desirable that both values in a pair increase at once. It would be great to define an instance of the class Incable
for pairs as follows: instance (Incable t1, Incable t2) => Incable (t1, t2) where inc (x1, x2) = (inc x1, inc x2)
ghci> inc (1, 2) <interactive>:105:1: Overlapping instances for Incable (t0, t1) arising from a use of `inc' Matching instances: instance (Functor f, Incable t) => Incable (ft) -- Defined at src/Main.hs:16:10 instance (Incable t1, Incable t2) => Incable (t1, t2) -- Defined at src/Main.hs:18:10 In the expression: inc (1, 2) In an equation for `it': it = inc (1, 2)
Incable
for all functors, we immediately defined it for pairs. Add to this that in GHC the definition of a class instance cannot be hidden during import. That is, we get unnecessary behavior of the pair as a functor into the load to those capabilities that we really need.inc (1.0, 2, 3)
? It would seem that here we definitely should have no problems - the triples were not defined as functors, which means we can implement instances of the Incable
class for them as we see fit: instance (Incable t1, Incable t2, Incable t3) => Incable (t1, t2, t3) where inc (x1, x2, x3) = (inc x1, inc x2, inc x3)
ghci> inc (1.0, 2, 3) <interactive>:14:1: Overlapping instances for Incable (t0, t1, t2) arising from a use of `inc' Matching instances: instance (Functor f, Incable t) => Incable (ft) -- Defined at src/Main.hs:18:10 instance (Incable t1, Incable t2, Incable t3) => Incable (t1, t2, t3) -- Defined at src/Main.hs:20:10 In the expression: inc (1.0, 2, 3) In an equation for `it': it = inc (1.0, 2, 3)
ghci> inc (1.0, 2, 3) <interactive>:12:1: No instance for (Functor ((,,) t0 t1)) arising from a use of `inc' Possible fix: add an instance declaration for (Functor ((,,) t0 t1)) In the expression: inc (1.0, 2, 3) In an equation for `it': it = inc (1.0, 2, 3)
Functor
to define an instance of the class Functor
for the troika as we need it? instance Functor ((,,) t1 t2) where fmap f (x1, x2, x3) = (fmap f x1, fmap f x2, fmap f x3)
[1 of 1] Compiling Main ( src/Main.hs, interpreted ) src/Main.hs:19:36: Couldn't match expected type `b' with actual type `f0 b' `b' is a rigid type variable bound by the type signature for fmap :: (a -> b) -> (t1, t2, a) -> (t1, t2, b) at src/Main.hs:19:5 In the return type of a call of `fmap' In the expression: fmap f x3 In the expression: (x1, x2, fmap f x3) src/Main.hs:19:43: Couldn't match expected type `a' with actual type `f0 a' `a' is a rigid type variable bound by the type signature for fmap :: (a -> b) -> (t1, t2, a) -> (t1, t2, b) at src/Main.hs:19:5 In the second argument of `fmap', namely `x3' In the expression: fmap f x3 In the expression: (x1, x2, fmap f x3) Failed, modules loaded: none.
instance Functor ((,,) t1 t2) where fmap f (x1, x2, x3) = (x1, x2, fmap f x3)
[1 of 1] Compiling Main ( src/Main.hs, interpreted ) src/Main.hs:19:36: Couldn't match expected type `b' with actual type `f0 b' `b' is a rigid type variable bound by the type signature for fmap :: (a -> b) -> (t1, t2, a) -> (t1, t2, b) at src/Main.hs:19:5 In the return type of a call of `fmap' In the expression: fmap f x3 In the expression: (x1, x2, fmap f x3) src/Main.hs:19:43: Couldn't match expected type `a' with actual type `f0 a' `a' is a rigid type variable bound by the type signature for fmap :: (a -> b) -> (t1, t2, a) -> (t1, t2, b) at src/Main.hs:19:5 In the second argument of `fmap', namely `x3' In the expression: fmap f x3 In the expression: (x1, x2, fmap f x3) Failed, modules loaded: none.
Functor
for couples? Secondly, how is it possible (and is it even possible) to give a similar definition for tuples with more than two elements (for example, for a triple)?Functor
for a pair, only one parameter is indicated, and not two?Functor
for tuples of the same type, that is, tuples of the type (t, t)
, (t, t, t)
, etc. At first glance, such Tuples are no different from lists, but their important feature is that they are tough, at the compilation stage, they specify the number of their elements. Such types can represent, for example, pairs and triples of integers that must be processed simultaneously and in the same way. In the general case, it would be more correct to use multiparameter functors. class Functor2 f where fmap2 :: (a1 -> b1) -> (a2 -> b2) -> f a1 a2 -> f b1 b2
instance Functor ((,,) t1 t2) where fmap f (x1, x2, x3) = (x1, x2, f x3)
instance Functor ((,,) t1 t2) where fmap f (x1, x2, x3) = (f x1, f x2, f x3)
[1 of 1] Compiling Main (src / Main.hs, interpreted) src / Main.hs: 19: 28: Couldn't match type `b 'with` t2' `b 'is a rigid type variable bound by the type signature for fmap :: (a -> b) -> (t1, t2, a) -> (t1, t2, b) at src / Main.hs: 19: 5 `t2 'is a rigid type variable bound by the instance declaration at src / Main.hs: 18: 10 Expected type: t1 Actual type: b In the return type of a call of `f ' In the expression: f x1 In the expression: (f x1, f x2, f x3) src / Main.hs: 19: 30: Couldn't match type `t1 'with` t2' `t1 'is a rigid type variable bound by the instance declaration at src / Main.hs: 18: 10 `t2 'is a rigid type variable bound by the instance declaration at src / Main.hs: 18: 10 Expected type: a Actual type: t1 In the first argument of `f ', namely` x1' In the expression: f x1 In the expression: (f x1, f x2, f x3) src / Main.hs: 19: 34: Couldn't match type `a 'with` t2' `a 'is a rigid type variable bound by the type signature for fmap :: (a -> b) -> (t1, t2, a) -> (t1, t2, b) at src / Main.hs: 19: 5 `t2 'is a rigid type variable bound by the instance declaration at src / Main.hs: 18: 10 Expected type: t2 Actual type: b In the return type of a call of `f ' In the expression: f x2 In the expression: (f x1, f x2, f x3) Failed, modules loaded: none.
Functor
class are not provided in the system library. I suspect that the developers simply needed the behavior of the functor for pairs somewhere "in place", and then they found it useful to raise it to the system level. To test this version, the easiest way is to rebuild the system library without defining pairs as functors, but I don’t have time for such an experiment right now.id
. Unlike globally defined instances, such reduced display functions are easily hidden when necessary when importing the corresponding module.Source: https://habr.com/ru/post/259275/
All Articles