{"action":"created","issue":{"url":"https://api.github.com/repos/purescript/purescript/issues/1922","repository_url":"https://api.github.com/repos/purescript/purescript","labels_url":"https://api.github.com/repos/purescript/purescript/issues/1922/labels{/name}","comments_url":"https://api.github.com/repos/purescript/purescript/issues/1922/comments","events_url":"https://api.github.com/repos/purescript/purescript/issues/1922/events","html_url":"https://github.com/purescript/purescript/issues/1922","id":138678481,"number":1922,"title":"Coercible newtypes and field accessors","user":{"login":"agrafix","id":1106569,"avatar_url":"https://avatars.githubusercontent.com/u/1106569?v=3","gravatar_id":"","url":"https://api.github.com/users/agrafix","html_url":"https://github.com/agrafix","followers_url":"https://api.github.com/users/agrafix/followers","following_url":"https://api.github.com/users/agrafix/following{/other_user}","gists_url":"https://api.github.com/users/agrafix/gists{/gist_id}","starred_url":"https://api.github.com/users/agrafix/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/agrafix/subscriptions","organizations_url":"https://api.github.com/users/agrafix/orgs","repos_url":"https://api.github.com/users/agrafix/repos","events_url":"https://api.github.com/users/agrafix/events{/privacy}","received_events_url":"https://api.github.com/users/agrafix/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":13,"created_at":"2016-03-05T13:24:22Z","updated_at":"2016-03-07T18:16:44Z","closed_at":null,"body":"Currently all records can be accessed by the `.`, eg `foo.bar` reads the field foo of a record \r\n\r\n```purescript\r\ntype FooRec x = { bar :: Int | x }\r\n```\r\n\r\nNow if I define a newtype\r\n```purescript\r\nnewtype FooRec' x = FooRec' { bar :: Int | x }\r\n```\r\n\r\ntrying to read a value with `foo.bar` produces a type error, which of corse is expected. What you'd have to do is unwrap the value first, and then access the field. Or use lenses. But both become a little bit unhandy when you have nested data structures like\r\n\r\n```purescript\r\nnewtype A = A { b :: B }\r\nnewtype B = B { c :: C }\r\nnewtype C = C { value :: Int }\r\n```\r\n\r\nIf I have a value of `wrappedA :: A` and want the `value` field of the contained `C`, then would like to write `wrappedA.b.c.value`, but that's not possible because I have to unwrap after every field access.\r\n\r\nNow Haskell has included a type class in `base 4.7`\r\n\r\n```haskell\r\nclass Coercible a b\r\n\r\ncoerce :: Coercible a b => a -> b\r\n```\r\n(see https://hackage.haskell.org/package/base-4.8.2.0/docs/Data-Coerce.html) and the compiler automatically generates instances for things that have the same representation. We could limit that to newtypes for now (and maybe arrays/lists of newtypes) like so:\r\n\r\n```purescript\r\nnewtype Foo = Foo { bar :: Int }\r\n\r\n-- always holds:\r\ninstance coercibleSameType :: Coercible a a\r\n\r\n-- generated automatically:\r\ninstance coercibleFooRec :: Coercible Foo { bar :: Int }\r\n\r\n-- not sure if we want these too?\r\ninstance coercibleRecFoo :: Coercible { bar :: Int } Foo\r\ninstance coercibleFooArray :: Coercible (Array Foo) (Array { bar :: Int })\r\n-- ...\r\n```\r\n\r\nNow we could introduce a new way of accessing fields so that `wrappedA.b.c.value` from above desugars to `(coerce (coerce (coerce wrappedA).b).c).value`. This would also work if there would be unwrapped records along the path due to `Coercible a a`. As `coerce` is a runtime No-op, the compile should probably optimize it away after type checking."},"comment":{"url":"https://api.github.com/repos/purescript/purescript/issues/comments/193377494","html_url":"https://github.com/purescript/purescript/issues/1922#issuecomment-193377494","issue_url":"https://api.github.com/repos/purescript/purescript/issues/1922","id":193377494,"user":{"login":"AppShipIt","id":48431,"avatar_url":"https://avatars.githubusercontent.com/u/48431?v=3","gravatar_id":"","url":"https://api.github.com/users/AppShipIt","html_url":"https://github.com/AppShipIt","followers_url":"https://api.github.com/users/AppShipIt/followers","following_url":"https://api.github.com/users/AppShipIt/following{/other_user}","gists_url":"https://api.github.com/users/AppShipIt/gists{/gist_id}","starred_url":"https://api.github.com/users/AppShipIt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/AppShipIt/subscriptions","organizations_url":"https://api.github.com/users/AppShipIt/orgs","repos_url":"https://api.github.com/users/AppShipIt/repos","events_url":"https://api.github.com/users/AppShipIt/events{/privacy}","received_events_url":"https://api.github.com/users/AppShipIt/received_events","type":"User","site_admin":false},"created_at":"2016-03-07T18:16:44Z","updated_at":"2016-03-07T18:16:44Z","body":"Would it provide any benefit to #514? I tried to google its relationship to `GeneralizedNewTypeDeriving` and just found [complexity](http://ezyang.tumblr.com/post/96448232652/safe-zero-cost-coercions-for-haskell-richard)."}}