Opened 2 years ago

Last modified 2 years ago

#13592 new feature request

Newtype type class with compiler generated instances

Reported by: Iceland_jack Owned by:
Priority: normal Milestone:
Component: Compiler Version: 8.0.1
Keywords: LevityPolymorphism Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: None/Unknown Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s):
Wiki Page:

Description

Define a Newtype class, autmatically generating instances

class Newtype n where
  type O n :: Type

  pack   :: O n -> n
  unpack :: n   -> O n

as defined in Conal's Generic parallel functional programming but also found in the newtype and lens packages.

I run into this class every once in a while

Change History (5)

comment:1 Changed 2 years ago by RyanGlScott

I'm leery about adding more magic classes to GHC, but fortunately, this magic already exists as Data.Coerce.Coercible:

import Data.Coerce

pack :: Coercible on n => on -> n
pack = coerce

unpack :: Coercible n on => n -> on
unpack = coerce

newtype Example = Example String deriving Show

main :: IO ()
main = do
  print (pack "hello" :: Example)
  print (unpack (Example "world") :: String)

Does this suit your needs?

comment:2 Changed 2 years ago by Iceland_jack

Last edited 2 years ago by Iceland_jack (previous) (diff)

comment:3 Changed 2 years ago by Iceland_jack

Last edited 2 years ago by Iceland_jack (previous) (diff)

comment:4 Changed 2 years ago by Iceland_jack

Last edited 2 years ago by Iceland_jack (previous) (diff)

comment:5 Changed 2 years ago by Iceland_jack

Keywords: LevityPolymorphism added

ala:

ala Sum foldMap [1,2]
  :: Num o 
  => o

while coerce lacks a way to connect a newtype to its associated type

ala Sum foldMap [1,2]
  :: Coercible o o'
  => Num o
  => o'

but it could certainly re-use Coercible either as default methods — compiler only needs to generate instance Newtype (Sum a) where type O (Sum a) = a

class Newtype n where
  type O n
  pack :: O n -> n
  pack = coerce
  default
    pack :: O n `Coercible` n => O n -> n

  unpack :: n -> O n
  unpack = coerce
  default
    unpack :: n `Coercible` O n => n -> O n

or with Coercible as a superclass — compiler only needs to generate type instance O (Sum a) = a and Newtype is definable by users

class    O n `Coercible` n => Newtype n
instance O n `Coercible` n => Newtype n

-- type instance O (a, b) = (O a, O b)

pack :: Newtype n => O n -> n
pack = coerce

unpack :: Newtype n => n -> O n
unpack = coerce

I see some problems with newtypes wrapping polymorphic values, #13901

newtype Nat = Nat (forall a. (a -> a) -> (a -> a))

-- • Illegal polymorphic type: forall a. (a -> a) -> (a -> a)
-- • In the equations for closed type family ‘O’
type instance O Nat = forall a. (a -> a) -> (a -> a) 

TODO With newtypes over unlifted types and levity polymorphic Coercible (#13595) we can define

newtype MyInt  = MkInt Int 
newtype MyInt# = MkInt# Int#

-- ==>

type family   O (a :: TYPE rep) :: TYPE rep
type instance O MyInt  = Int
type instance O MyInt# = Int#
Last edited 2 years ago by Iceland_jack (previous) (diff)
Note: See TracTickets for help on using tickets.