A type synonym causes a type error

As a continuation of my previous question Using makeLenses, class restrictions, and type synonyms together I have a new type error that I would like to understand.

A type error is caused by the introduction of a type synonym of type S = (Num n) => State n in the example below.

 {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE RankNTypes #-} module Foo where import Control.Lens data State a = State { _a :: a } deriving Show makeLenses ''State -- Requires TemplateHaskell -- | Smart constructor enforcing class constraint on record field _a. mkState :: (Num a) => a -> State a mkState n = State {_a = n} doStuff1 :: Num a => State a -> State a doStuff1 s = s & a %~ (*2) test1a = doStuff1 $ mkState 5 -- results in State {_a = 10.0} test1b = doStuff1 $ mkState 5.5 -- results in State {_a = 11.0} type S = (Num n) => State n -- Requires the RankNTypes extensions doStuff2 :: S -> S doStuff2 s = s & a %~ (*2) test2a = doStuff2 $ mkState 5 -- Results in State {_a = 10.0} --test2b = doStuff2 $ mkState 5.5 -- Type error. 

If I uncomment test2b , I get the following error.

 Could not deduce (Fractional n) arising from the literal `5.5' from the context (Num n) bound by a type expected by the context: Num n => State n at Foo.hs:32:10-32 Possible fix: add (Fractional n) to the context of a type expected by the context: Num n => State n In the first argument of `mkState', namely `5.5' In the second argument of `($)', namely `mkState 5.5' In the expression: doStuff2 $ mkState 5.5 

I would like to be able to understand why the type synonym introduced causes this error and how to decrypt the error message.

+3
source share
1 answer

S -> S not equivalent to forall n. Num n => State n -> State n forall n. Num n => State n -> State n . This is equivalent to (forall n. Num n => State n) -> (forall n. Num n => State n) . The first means that for all numerical types n we can go to State n and return a State n (for the same type n ). The latter means that we pass something that may be State n for all numeric types of n , and we return what could be State n for all types of n . In other words, the argument and the result are polymorphic.

This means that the argument you pass must be of type Num n => State n , and not a more specific type, for example, State Int . This is true for 5 , which is of type Num n => n , but not 5.5 , which is of type Fractional n => n .

+9
source

Source: https://habr.com/ru/post/988360/


All Articles