GeneralizedNewtypeDeriving ! is!now!type+safe! How!roles!save!the!day Richard!Eisenberg University!of!Pennsylvania eir@cis.upenn.edu Haskell!Implementors’!Workshop Sunday,!September!22,!2013 Boston,!MA,!USA
GHC!7.6.3! � !segfault newtype7Age7=7MkAge7Int 77deriving7Frob type7family7Discern7a type7instance7Discern7Int7=7Bool type7instance7Discern7Age7=7[Char] class7Frob7a7where 77baz7::7a7 � 7Discern7a instance7Frob7Int7where 77baz7=7(>70) segfault7=7head7(baz7(MkAge75))
GHC!7.6.3! � !segfault newtype7Age7=7MkAge7Int 77deriving7Frob type7family7Discern7a type7instance7Discern7Int7=7Bool type7instance7Discern7Age7=7[Char] class7Frob7a7where 77baz7::7a7 � 7Discern7a instance7Frob7Int7where 77baz7=7(>70) segfault7=7head7(baz7(MkAge75))
Two!equalities Nominal!(N)!equality:!two!types!are!the! same . • reflexivity “Haskell!equality” • type!synonyms “compile+time!equality” • type!families • GADT!pattern+matching • any!use!of!( ~ ) Representational!(R)!equality:!two!types!have! the!same! runtime*representation . • newtypes “runtime!equality” • any!nominal!equality R+equality!is! coarser !than!N+equality
Safety!of!GND • GeneralizedNewtypeDeriving !(GND)! requires!representational!equality: class7C7a7where7... deriving7instance7C7Age � !soundness!requires!( C7Age ! ~ R!! C7Int ) • How!do!we!know!if!this!holds? � !depends!on!the!definition!of! C • Use!a!role!for!the!parameter! a
Parameter!roles • All!type!parameters!have!a!role: data7Foo7b7=7... If! b !is!nominal: Foo7Age7 ~ R 7Foo7Int If! b !is!representational: Foo7Age7 ~ R 7Foo7Int • b ’s!role!says!what!notion!of!equality!between! Baz !and! Boz !is!necessary!to!prove!that! Foo7 Baz !is!representationally!equal!to! Foo7Boz . • A!parameter!at!representational!role!is!more! flexible!because!R+equality!is!coarser!than!N+ equality
Type+safe!GND Last!parameter!of!a!class!has!representational!role � GND!is!type+safe.
Role!inference • Roles!are!inferred!from!a!type’s!definition • A!role!is!representational!by!default,!or!nominal! if!a!parameter!is!used!in!a!nominal!context • Nominal!contexts: ✦ Type!families ✦ GADT+like!parameters ✦ Use!with!( ~ ) ✦ Other!nominal!contexts ✦ plus!one!more...
Roles!examples class7C17a7where7m17::7a7 � 7[a] � ! a !is!representational class7C27a7where7m27::7a7 � 7Discern7a � ! a !is!nominal data7T17a7=7MkT17a � ! a !is!representational data7T27a7where7MkT27::7T27Bool � ! a !is!nominal data7T37a7=7MkT37(T27a) � ! a !is!nominal
Tricky!role!inference data7Tricky7a7b7=7MkTricky7(a7b) � ! a !is!representational,! b !is!nominal
Role!inference • Roles!are!inferred!from!a!type’s!definition • A!role!is!representational!by!default,!or!nominal! if!a!parameter!is!used!in!a!nominal!context • Nominal!contexts: ✦ Type!families ✦ GADT+like!parameters ✦ Use!with!( ~ ) ✦ Other!nominal!contexts ✦ Argument!to!another!type!variable
Role!annotations type7role7Set7nominal data7Set7a7=7... instance7Ord7Age7where7... 77SS7inverse7of7Int’s7Ord7instance class7HasSet7a7where7mkSet7::7Set7a instance7HasSet7Int7where7mkSet7=7... deriving7instance7HasSet7Age
Role!annotations type7role7Set7nominal data7Set7a7=7... instance7Ord7Age7where7... 77SS7inverse7of7Int’s7Ord7instance class7HasSet7a7where7mkSet7::7Set7a instance7HasSet7Int7where7mkSet7=7... Can't7make7a7derived7instance7of7 ‛ HasSet7Age’ 77(even7with7cunning7newtype7deriving): deriving7instance7HasSet7Age 77it7is7not7typeSsafe7to7use7GeneralizedNewtypeDeriving7on7this7class; 77the7last7parameter7of7 ‛ HasSet’7is7at7role7nominal
Roles!break!code!(1) • Increase!in!type!safety! � !less!code!compiles • Case!study:!Only!2!changes!required!in!GHC • In! cmm/SMRep.lhs : newtype7StgWord7=7StgWord7Word64 77deriving7(IArray7UArray,7...) • In! Data.Array.Base : class7IArray7a7e7where 77bounds7::7Ix7i7 � 7a7i7e7 � 7(i,7i) 77... • Had!to!manually!write!wrapper!functions
Roles!break!code!(2) • Increase!in!type!safety! � !less!code!compiles • Case!study:!Only!2!changes!required!in!GHC • In! utils/UniqFM.lhs : newtype7UniqFM7ele7=7UFM7(IntMap7ele) 77deriving7(Traversable,7...) • In! Data.Traversable : class7(...)7 � 7Traversable7t7where 77traverse7::7...7 � 7f7(t7b) 77... • Just!add! SXDeriveTraversable
Roles!in!GHC • Most!functions!that!produce!a! Coercion !now! take!a! Role : mkTyConAppCo7::7Role7S>7TyCon 7777777777777S>7[Coercion]7S>7Coercion dsTcCoercion7::7Role7S>7TcCoercion 7777777777777S>7(Coercion7S>7CoreExpr) 7777777777777S>7DsM7CoreExpr • Role!conversion!is!available: maybeSubCo2_maybe7::7Role77SS7desired 777777777777777777S>7Role77SS7current 777777777777777777S>7Coercion7S>7Maybe7Coercion • How!to!know!which!role!to!use?!See! ghc/docs/core*spec/core*spec.pdf
Roles!in!libraries • Step!1:!Make!sure!your!code!compiles ‣ diagrams !didn’t!due!to!potential!bug ‣ ...!but! lens !did,!as!did!every!other!library!tested • Step!2:!Think!about!adding!role!annotations ‣ Set ,! Map ‣ Other!abstract!types!with!class+based! invariants ‣ Use!CPP!to!keep!compatibility!with!older! versions!of!GHC
Further!reading • “Generative!Type!Abstraction!and!Type+Level! Computation”!by!Weirich,!Vytiniotis,!Peyton! Jones,!and!Zdancewic!(POPL!’11) • Roles!wiki!page: http://ghc.haskell.org/trac/ghc/wiki/Roles • Roles!implementation!wiki!page: http://ghc.haskell.org/trac/ghc/wiki/ RolesImplementation • Blog!post: http://typesandkinds.wordpress.com/ 2013/08/15/roles+a+new+feature+of+ghc/
Recommend
More recommend