Type synonym causes type error

痞子三分冷 提交于 2019-12-12 14:47:15

问题


As a follow-up to my previous question Using makeLenses, class constraints and type synonyms together I've got a new type error I would like to understand.

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

{-# 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 introduced type synonym causes this error and how to decipher the error message.


回答1:


S -> S is not equivalent to forall n. Num n => State n -> State n. It's equivalent to (forall n. Num n => State n) -> (forall n. Num n => State n). The former would mean that, for all numeric types n, we can pass in a State n and get back a State n (for the same type n). The latter means that we pass in something that can be a State n for all numeric types n and we get back something that can be a State n for all type n. In other words both the argument and the result are polymorphic.

What this means is that the argument you pass in must have type Num n => State n, not a more concrete type like, say, State Int. This is true for 5, which has the type Num n => n, but not 5.5, which has the type Fractional n => n.



来源:https://stackoverflow.com/questions/31772516/type-synonym-causes-type-error

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!