well-typed / optics

Optics as an abstract interface
375 stars 24 forks source link

Better errors for generic optics #384

Closed arybczak closed 3 years ago

arybczak commented 3 years ago
λ> data User = User { name :: String, age :: Int }
Before ```haskell λ> User "Tom" 30 ^? gafield @"name" :22:18: error: • Type ‘User’ doesn't have a Generic instance • In the second argument of ‘(^?)’, namely ‘gafield @"name"’ In the expression: User "Tom" 30 ^? gafield @"name" In an equation for ‘it’: it = User "Tom" 30 ^? gafield @"name" :22:18: error: • Type ‘User’ doesn't have a field named ‘name’ • In the second argument of ‘(^?)’, namely ‘gafield @"name"’ In the expression: User "Tom" 30 ^? gafield @"name" In an equation for ‘it’: it = User "Tom" 30 ^? gafield @"name" λ> User "Tom" 30 ^? gposition @0 :23:1: error: • There is no 0th position • When checking the inferred type it :: forall a. GPositionSum (TypeError ...) (Rep User) (Rep User) a a => Maybe a λ> User "Tom" 30 ^? gconstructor @"User" :24:1: error: • Type ‘User’ doesn't have a constructor named ‘User’ • When checking the inferred type it :: forall a. GConstructorSum (FromRight (TypeError ...) (GetNamePath "User" (Rep User) '[])) (Rep User) (Rep User) a a => Maybe a ```
After ```haskell λ> User "Tom" 30 ^? gafield @"name" :11:18: error: • Type ‘User’ doesn't have a Generic instance • In the second argument of ‘(^?)’, namely ‘gafield @"name"’ In the expression: User "Tom" 30 ^? gafield @"name" In an equation for ‘it’: it = User "Tom" 30 ^? gafield @"name" λ> User "Tom" 30 ^? gposition @0 :12:18: error: • Type ‘User’ doesn't have a Generic instance • In the second argument of ‘(^?)’, namely ‘gposition @0’ In the expression: User "Tom" 30 ^? gposition @0 In an equation for ‘it’: it = User "Tom" 30 ^? gposition @0 λ> User "Tom" 30 ^? gconstructor @"User" :13:18: error: • Type ‘User’ doesn't have a Generic instance • In the second argument of ‘(^?)’, namely ‘gconstructor @"User"’ In the expression: User "Tom" 30 ^? gconstructor @"User" In an equation for ‘it’: it = User "Tom" 30 ^? gconstructor @"User" ```

λ> data User = User { name :: String, age :: Int } deriving Generic
Before ```haskell λ> User "Tom" 30 ^? gfield @"salary" :42:1: error: • Data constructor ‘User’ doesn't have a field named ‘salary’ • When checking the inferred type it :: forall a. (HasField "salary" User a, GSetFieldProd (TypeError ...) (S1 ('MetaSel ('Just "name") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String) :*: S1 ('MetaSel ('Just "age") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int)) (S1 ('MetaSel ('Just "name") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String) :*: S1 ('MetaSel ('Just "age") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int)) a) => Maybe a λ> User "Tom" 30 ^? gposition @0 :45:1: error: • There is no 0th position • When checking the inferred type it :: forall a. GPositionSum (TypeError ...) (M1 C ('MetaCons "User" 'PrefixI 'True) (S1 ('MetaSel ('Just "name") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String) :*: S1 ('MetaSel ('Just "age") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int))) (M1 C ('MetaCons "User" 'PrefixI 'True) (S1 ('MetaSel ('Just "name") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String) :*: S1 ('MetaSel ('Just "age") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int))) a a => Maybe a λ> User "Tom" 30 ^? gposition @4 :43:1: error: • Data constructor ‘User’ has 2 fields, 4th requested • When checking the inferred type it :: forall a. GFieldProd (TypeError ...) (S1 ('MetaSel ('Just "name") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String) :*: S1 ('MetaSel ('Just "age") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int)) (S1 ('MetaSel ('Just "name") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String) :*: S1 ('MetaSel ('Just "age") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int)) a a => Maybe a λ> User "Tom" 30 ^? gconstructor @"User1" :44:1: error: • Type ‘User’ doesn't have a constructor named ‘User1’ • When checking the inferred type it :: forall a. GConstructorSum (TypeError ...) (M1 C ('MetaCons "User" 'PrefixI 'True) (S1 ('MetaSel ('Just "name") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String) :*: S1 ('MetaSel ('Just "age") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int))) (M1 C ('MetaCons "User" 'PrefixI 'True) (S1 ('MetaSel ('Just "name") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 String) :*: S1 ('MetaSel ('Just "age") 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 Int))) a a => Maybe a ```
After ```haskell λ> User "Tom" 30 ^? gfield @"salary" :23:18: error: • Data constructor ‘User’ doesn't have a field named ‘salary’ • In the second argument of ‘(^?)’, namely ‘gfield @"salary"’ In the expression: User "Tom" 30 ^? gfield @"salary" In an equation for ‘it’: it = User "Tom" 30 ^? gfield @"salary" λ> User "Tom" 30 ^? gposition @0 :26:18: error: • There is no 0th position • In the second argument of ‘(^?)’, namely ‘gposition @0’ In the expression: User "Tom" 30 ^? gposition @0 In an equation for ‘it’: it = User "Tom" 30 ^? gposition @0 λ> User "Tom" 30 ^? gposition @4 :24:18: error: • Data constructor ‘User’ has 2 fields, 4th requested • In the second argument of ‘(^?)’, namely ‘gposition @4’ In the expression: User "Tom" 30 ^? gposition @4 In an equation for ‘it’: it = User "Tom" 30 ^? gposition @4 λ> User "Tom" 30 ^? gconstructor @"User1" :25:18: error: • Type ‘User’ doesn't have a constructor named ‘User1’ • In the second argument of ‘(^?)’, namely ‘gconstructor @"User1"’ In the expression: User "Tom" 30 ^? gconstructor @"User1" In an equation for ‘it’: it = User "Tom" 30 ^? gconstructor @"User1" ```