Polymorphic lens without template haskell - haskell

I am trying to create a polymorphic lens decleration (without template haskell) for multiple types.
module Sample where
import Control.Lens
data A = A {_value:: Int}
data B = B {_value:: Int}
data C = C {_value:: String}
value = lens _value (\i x -> i{_value=x}) -- <<< ERROR
But I get following error:
Ambiguous occurrence ‘_value’
It could refer to either the field ‘_value’,
defined at library/Sample.hs:5:13
or the field ‘_value’, defined at
library/Sample.hs:4:13
or the field ‘_value’, defined at
library/Sample.hs:3:13
|
6 | value = lens _value (\i x -> i{_value=x}) -- <<< ERROR
| ^^^^^^
So, goal is to have value lens to work on all three types A, B and C. Is there a way to achieve that?
Thanks.

Lenses can be derived without TH by generic-lens. You can specialize the generic field lens to a specific field and give it a name as follows.
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeApplications #-}
import GHC.Generics (Generic)
import Control.Lens (Lens, (^.))
import Data.Generics.Product (HasField(field))
data A = A { _value :: Int } deriving Generic
data B = B { _value :: Int } deriving Generic
data C = C { _value :: String } deriving Generic
value :: HasField "_value" s t a b => Lens s t a b
value = field #"_value"
main :: IO ()
main = print (A 0 ^. value, B 0 ^. value, C "0" ^. value)

Haskell does not support overloading functions the way a language like Java or C++ does. To do what you want you need to use a typeclass like so.
class HasValue a b where
value :: Lens' a b
data A = A {_valueA:: Int}
data B = B {_valueB:: Int}
data C = C {_valueC:: String}
instance HasValue A Int where
value = lens _valueA (\i x -> i{_valueA=x})
instance HasValue B Int where
value = lens _valueB (\i x -> i{_valueB=x})
instance HasValue C String where
value = lens _valueC (\i x -> i{_valueC=x}
You'll need to enable multiparameter typeclasses to do this.

If you want to avoid DuplicateRecordFields, another option is to define everything in its own module, though this will require qualified imports for them to be imported into the same module.
module Sample.A where
import Control.Lens
data A = A {_value:: Int}
value = lens _value (\i x -> i{_value=x})
module Sample.B where
import Control.Lens
data B = B {_value:: Int}
value = lens _value (\i x -> i{_value=x})
module Sample.C where
import Control.Lens
data C = C {_value:: String}
value = lens _value (\i x -> i{_value=x})
module Main where
import qualified Sample.A as A
import qualified Sample.B as B
import qualified Sample.C as C
main :: IO ()
main = print (A.A 0 ^. A.value, B.B 0 ^. B.value, C.C "0" ^. C.value)

Related

Filter a list by returning only one kind of data constructor instead of the type of the type constructor

So let's say I have the following data type :
data CommandRequest = CreateWorkspace {commandId :: UUID , workspaceId ::UUID }
| IntroduceIdea {commandId :: UUID , workspaceId ::UUID , ideaContent :: String} deriving (Show,Eq)
with the {-# LANGUAGE DataKinds #-}
I want to implement the following function (in pseudocode) :
filter :: [CommandRequest] -> [CreateWorkspace] (promoting the data constructor to a type level)
can you help me with the implementation of that function ?... Thank you !
Given a Haskell type like:
data Foo = Bar Int | Baz String
there is no direct way of writing down a new type that represents the subset of values of type Foo that are constructed with Bar, even using the DataKinds extension.
In particular, when you turn on DataKinds, the Bar type that you get is not the type of the values Bar 1 and Bar 2. In fact, the new lifted Bar type doesn't really have anything to do with the values Bar 1 and Bar 2, except for the fact that they share the name Bar. It's not that different than explicitly defining:
data True = TrueThing
This new type True has nothing to do with the value True of type Bool, except they happen to have the same name.
Presuming that what you are trying to do is find a type-safe way of representing the result of filtering CommandRequest for just those values that were constructed with the CreateWorkspace constructor so that you can't "accidentally" let an IntroduceIdea sneak in to your list, you'll have to take another approach. There are several possibilities.
The most straightforward way, which doesn't require any special type-level programming at all, is to represent CreateWorkspace and IntroduceIdea as separate types:
{-# LANGUAGE DuplicateRecordFields #-}
data CreateWorkspace = CreateWorkspace
{ commandId :: UUID
, workspaceId ::UUID
} deriving (Show)
data IntroduceIdea = IntroduceIdea
{ commandId :: UUID
, workspaceId ::UUID
, ideaContent :: String
} deriving (Show)
and then create a new algebraic sum type to represent the disjoint union of those separate types:
data CommandRequest
= CreateWorkspace' CreateWorkspace
| IntroduceIdea' IntroduceIdea
deriving (Show)
Note we've used the ticks to differentiate these constructors from those used in the underlying component types. A simple variant of this would be to move common fields (like commandId, and perhaps workSpaceId) into the CommandRequest type. This might or might not make sense, depending on what you're trying to accomplish.
Anyway, this adds a little syntactic fluff, but it's straightforward to define:
filterCreateWorkspace :: [CommandRequest] -> [CreateWorkspace]
filterCreateWorkspace crs = [ cw | CreateWorkspace' cw <- crs ]
and with some additional "constructors":
createWorkspace :: UUID -> UUID -> CommandRequest
createWorkspace u1 u2 = CreateWorkspace' (CreateWorkspace u1 u2)
introduceIdea :: UUID -> UUID -> String -> CommandRequest
introduceIdea u1 u2 s = IntroduceIdea' (IntroduceIdea u1 u2 s)
it's not too hard to create and filter [CommandRequest] lists:
type UUID = Int
testdata1 :: [CommandRequest]
testdata1
= [ createWorkspace 1 2
, createWorkspace 3 4
, introduceIdea 5 6 "seven"
]
test1 = filterCreateWorkspace testdata1
giving:
> test1
[CreateWorkspace {commandId = 1, workspaceId = 2}
,CreateWorkspace {commandId = 3, workspaceId = 4}]
This is almost certainly the correct approach for doing what you want to do. I mean, this is exactly what algebraic data types are for. This is what a Haskell program is supposed to look like.
"But no," I hear you say! "I want to spend endless hours fighting confusing type errors! I want to crawl down the dependent type rabbit hole. You know, for 'reasons'." Should I stand in your way? Can one man stand against the ocean?
If you really want to do this at the type level, you still want to define separate types for your two constructors:
data CreateWorkspace = CreateWorkspace
{ commandId :: UUID
, workspaceId ::UUID
} deriving (Show)
data IntroduceIdea = IntroduceIdea
{ commandId :: UUID
, workspaceId ::UUID
, ideaContent :: String
} deriving (Show)
As before, this makes it easy to represent a list of type [CreateWorkspace]. Now, the key to working at the type level will be finding a way to make it as difficult as possible to represent a list of type [CommandRequest]. A standard method would be to introduce a CommandRequest type class with instances for our two types, together with an existential type to represent an arbitrary type belonging to that class:
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE ExistentialQuantification #-}
type UUID = Int -- for the sake of examples
data CreateWorkspace = CreateWorkspace
{ commandId :: UUID
, workspaceId ::UUID
} deriving (Show)
data IntroduceIdea = IntroduceIdea
{ commandId :: UUID
, workspaceId ::UUID
, ideaContent :: String
} deriving (Show)
class CommandRequest a where
maybeCreateWorkspace :: a -> Maybe CreateWorkspace
instance CommandRequest CreateWorkspace where
maybeCreateWorkspace c = Just c
instance CommandRequest IntroduceIdea where
maybeCreateWorkspace _ = Nothing
data SomeCommandRequest = forall t . CommandRequest t => SomeCommandRequest t
Now we can define:
import Data.Maybe
filterCreateWorkspace :: [SomeCommandRequest] -> [CreateWorkspace]
filterCreateWorkspace = catMaybes . map getCW
where getCW (SomeCommandRequest cr) = maybeCreateWorkspace cr
which works fine, though the syntax is still a bit cumbersome:
testdata2 :: [SomeCommandRequest]
testdata2 = [ SomeCommandRequest (CreateWorkspace 1 2)
, SomeCommandRequest (CreateWorkspace 3 4)
, SomeCommandRequest (IntroduceIdea 5 6 "seven")
]
test2 = print $ filterCreateWorkspace testdata2
The test gives:
> test2
[CreateWorkspace {commandId = 1, workspaceId = 2}
,CreateWorkspace {commandId = 3, workspaceId = 4}]
The awkward thing about this solution is that we need a type class method for identifying the CreateWorkspace type. If we wanted to construct lists of each possible constructor, we'd need to add a new type class method for every single one, and we need to give a definition for the method for every instance (though we can get away with a default definition that returns Nothing for all but one instance, I guess). Anyway, that's nuts!
The mistake we made was making it difficult to represent a list of type [CreateWorkspace] instead of absurdly difficult. To make it absurdly difficult, we'll still want to represent our two constructors as separate types, but we'll make them instances of a data family keyed by constructor names lifted to the type level by the DataKinds extension. Now this is starting to look like a Haskell program!
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE TypeFamilies #-}
data CommandRequestC = CreateWorkspace | IntroduceIdea
data family CommandRequest (c :: CommandRequestC)
type UUID = Int -- for the sake of examples
data instance CommandRequest CreateWorkspace
= CreateWorkspaceCR
{ commandId :: UUID
, workspaceId ::UUID
} deriving (Show)
data instance CommandRequest IntroduceIdea
= IntroduceIdeaCR
{ commandId :: UUID
, workspaceId ::UUID
, ideaContent :: String
} deriving (Show)
What's going on here? Well, we introduced a new type CommandRequestC (the trailing C stands for "constructor") with two constructors CreateWorkspace and IntroduceIdea. The only purpose of these constructors was to lift them to the type level using DataKinds in order to use them as type-level tags for the CommandRequest data family. This is a very common way of using DataKinds, maybe the most common. In fact, the example you gave of the type ReadResult 'RegularStream StreamSlice was exactly this kind of usage. The type:
data StreamType = All | RegularStream
carries no useful data. The whole point of its existence is to lift the constructors All and RegularStream to type-level tags, so that ReadResult 'All StreamSlice and ReadResult 'RegularStream StreamSlice can be used to name two different related types, just like CommandRequest 'CreateWorkspace and CommandRequest 'IntroduceIdea name two different related types.
At this point, we have two separate types for our two constructors that happen to be related via a tagged data family, rather than via a type class.
testdata3 :: [CommandRequest 'CreateWorkspace]
testdata3 = [CreateWorkspaceCR 1 2, CreateWorkspaceCR 3 4]
testdata4 :: [CommandRequest 'IntroduceIdea]
testdata4 = [IntroduceIdeaCR 5 6 "seven"]
Note that even though we can write the type [CommandRequest c], leaving the constructor tag as an unspecified type variable c, we still can't write a list that mixes these constructors:
testdata5bad :: [CommandRequest c]
testdata5bad = [CreateWorkspaceCR 1 2, CreateWorkspaceCR 3 4,
IntroduceIdeaCR 5 6 "seven"] -- **ERROR**
We still need our existential type:
{-# LANGUAGE ExistentialQuantification #-}
data SomeCommandRequest = forall c . SomeCommandRequest (CommandRequest c)
and the extra existential syntax:
testdata6 :: [SomeCommandRequest]
testdata6 = [ SomeCommandRequest (CreateWorkspaceCR 1 2)
, SomeCommandRequest (CreateWorkspaceCR 3 4)
, SomeCommandRequest (IntroduceIdeaCR 5 6 "seven")]
Worse yet, if we try to write a filter function, it's not clear how to implement it. One reasonable first attempt is:
filterCreateWorkspace :: [SomeCommandRequest] -> [CommandRequest 'CreateWorkspace]
filterCreateWorkspace (SomeCommandRequest cr : rest)
= case cr of cw#(CreateWorkspaceCR _ _) -> cw : filterCreateWorkspace rest
_ -> filterCreateWorkspace rest
but this fails with an error about failing to match to the CreateWorkspace tag.
The problem is that data families aren't powerful enough to allow you to infer which member of a family you actually have (i.e., whether cr is a CreateWorkspaceCR or IntroduceIdeaCR). At this point, we could go back to working with a type class or maybe introduce proxies or singletons to maintain a value-level representation of the constructors in the existential type, but there's a more straightforward solution.
GADTs are powerful enough to infer the type of cr, and we can rewrite our data family as a GADT. Not only is the syntax simpler:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE StandaloneDeriving #-}
data CommandRequestC = CreateWorkspace | IntroduceIdea
type UUID = Int
data CommandRequest c where
CreateWorkspaceCR :: UUID -> UUID -> CommandRequest 'CreateWorkspace
IntroduceIdeaCR :: UUID -> UUID -> String -> CommandRequest 'IntroduceIdea
deriving instance Show (CommandRequest c)
data SomeCommandRequest = forall c . SomeCommandRequest (CommandRequest c)
but we can implement our filtering function without fuss:
filterCreateWorkspace :: [SomeCommandRequest] -> [CommandRequest 'CreateWorkspace]
filterCreateWorkspace crs
= [ cw | SomeCommandRequest cw#(CreateWorkspaceCR _ _) <- crs ]
define some helpful "constructors":
createWorkspace :: UUID -> UUID -> SomeCommandRequest
createWorkspace u1 u2 = SomeCommandRequest (CreateWorkspaceCR u1 u2)
introduceIdea :: UUID -> UUID -> String -> SomeCommandRequest
introduceIdea u1 u2 s = SomeCommandRequest (IntroduceIdeaCR u1 u2 s)
and test it:
testdata7 :: [SomeCommandRequest]
testdata7 = [ createWorkspace 1 2
, createWorkspace 3 4
, introduceIdea 5 6 "seven"]
test7 = filterCreateWorkspace testdata7
like so:
> test4
[CreateWorkspaceCR 1 2,CreateWorkspaceCR 3 4]
>
Does any of this look familiar? It should, because it's #chi's solution. And it's the only type-level solution that really makes sense, giving what you're trying to do.
Now, with a couple of type aliases and some clever renaming, you can technically get the type signature you want, like so:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE StandaloneDeriving #-}
data CommandRequestC = CreateWorkspaceC | IntroduceIdeaC
type CreateWorkspace = ACommandRequest 'CreateWorkspaceC
type IntroduceIdea = ACommandRequest 'IntroduceIdeaC
type UUID = Int
data ACommandRequest c where
CreateWorkspaceCR :: UUID -> UUID -> CreateWorkspace
IntroduceIdeaCR :: UUID -> UUID -> String -> IntroduceIdea
deriving instance Show (ACommandRequest c)
data CommandRequest = forall c . CommandRequest (ACommandRequest c)
filterCreateWorkspace :: [CommandRequest] -> [CreateWorkspace]
filterCreateWorkspace crs
= [ cw | CommandRequest cw#(CreateWorkspaceCR _ _) <- crs ]
createWorkspace :: UUID -> UUID -> CommandRequest
createWorkspace u1 u2 = CommandRequest (CreateWorkspaceCR u1 u2)
introduceIdea :: UUID -> UUID -> String -> CommandRequest
introduceIdea u1 u2 s = CommandRequest (IntroduceIdeaCR u1 u2 s)
testdata8 :: [CommandRequest]
testdata8 = [ createWorkspace 1 2
, createWorkspace 3 4
, introduceIdea 5 6 "seven"]
test8 = filterCreateWorkspace testdata8
but this is just a trick, so I wouldn't take it too seriously.
And, if all this seems like a lot of work and leaves you feeling dissatisfied with the resulting solution, then welcome to the world of type-level programming! (Actually, it is all kind of fun, but try not to expect too much.)
You can use a list comprehension to filter only those values obtained through a specific constructor. Note that the type of the list does not change.
filter :: [CommandRequest] -> [CommandRequest]
filter xs = [ x | x#(CreateWorkspace{}) <- xs ]
If you want a more precise type, you need more complex type-level machinery, like GADTs.
Here's an untested approach. You'll need a few extensions to be turned on.
data CR = CW | II -- to be promoted to "kinds"
-- A more precise, indexed type
data CommandRequestP (k :: CR) where
CreateWorkspace :: {commandId :: UUID, workspaceId ::UUID }
-> CommandRequestP 'CW
IntroduceIdea :: {commandId :: UUID, workspaceId ::UUID, ideaContent :: String}
-> CommandRequestP 'II
-- Existential wrapper, so that we can build lists
data CommandRequest where
C :: CommandRequestP k -> CommandRequest
filter :: [CommandRequest] -> [CommandRequestP 'CW]
filter xs = [ x | C (x#(CreateWorkspace{})) <- xs ]

Disambiguate record update with DuplicateRecordFields

I'm using the DuplicateRecordFields (+OverloadedLabels) extension, and I've run into a situation where I can't figure out how to disambiguate in a record update.
Here is a simplified example:
data A = A { name :: String }
data B = B { name :: String }
combine :: A -> B -> A
combine a b = a { name = name b }
Is there any way to make this work?
I answered in one of the previous questions about -XDuplicateRecordFields that currently GHC doesn't infer type of record field from its argument:
Silly duplicated record fields error
What you can do now is to specify type of name extractor explicitly, like this:
{-# LANGUAGE DuplicateRecordFields #-}
data A = A { name :: String }
data B = B { name :: String }
combine :: A -> B -> A
combine a b = a { name = (name :: B -> String) b }
Alternatively, you can mechanically use getField from GHC.Records to disambiguate, like this:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE TypeApplications #-}
module DRF where
import GHC.Records (getField)
data A = A { name :: String } deriving Show
data B = B { name :: String }
combine :: A -> B -> A
combine a b = a { name = getField #"name" b }
{- in ghci
Prelude DRF> a = A "Alice"
Prelude DRF> b = B "Bob"
Prelude DRF> DRF.combine a b
A {name = "Bob"}
-}
References:
https://www.reddit.com/r/haskell/comments/8693a3/usefulness_of_duplicaterecordfields/dw3fe8u/
https://hackage.haskell.org/package/base-4.12.0.0/docs/GHC-Records.html
You could match the name from a pattern:
data A = A { name :: String }
data B = B { name :: String }
combine :: A -> B -> A
combine a B{name = nb} = a { name = nb }
I'm not a fan of DuplicateRecordFields though. Why not instead go the lens route?
{-# LANGUAGE TemplateHaskell, FlexibleInstances, FunctionalDependencies #-}
import Control.Lens
import Control.Lens.TH
data A = A { _aName :: String }
makeFields ''A
data B = B { _bName :: String }
makeFields ''B
combine :: A -> B -> A
combine a b = a & name .~ b^.name

Haskell Export Record for Read Access Only

I have a Haskell type that uses record syntax.
data Foo a = Foo { getDims :: (Int, Int), getData :: [a] }
I don't want to export the Foo value constructor, so that the user can't construct invalid objects. However, I would like to export getDims, so that the user can get the dimensions of the data structure. If I do this
module Data.ModuleName(Foo(getDims)) where
then the user can use getDims to get the dimensions, but the problem is that they can also use record update syntax to update the field.
getDims foo -- This is allowed (as intended)
foo { getDims = (999, 999) } -- But this is also allowed (not intended)
I would like to prevent the latter, as it would put the data in an invalid state. I realize that I could simply not use records.
data Foo a = Foo { getDims_ :: (Int, Int), getData :: [a] }
getDims :: Foo a -> (Int, Int)
getDims = getDims_
But this seems like a rather roundabout way to work around the problem. Is there a way to continue using record syntax while only exporting the record name for read access, not for write access?
Hiding the constructor and then defining new accessor functions for each field is a solution, but it can get tedious for records with a large number of fields.
Here's a solution with the new HasField typeclass in GHC 8.2.1 that avoids having to define functions for each field.
The idea is to define an auxiliary newtype like this:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE PolyKinds #-} -- Important, obscure errors happen without this.
import GHC.Records (HasField(..))
-- Do NOT export the actual constructor!
newtype Moat r = Moat r
-- Export this instead.
moat :: r -> Moat r
moat = Moat
-- If r has a field, Moat r also has that field
instance HasField s r v => HasField s (Moat r) v where
getField (Moat r) = getField #s r
Every field in a record r will be accesible from Moat r, with the following syntax:
λ :set -XDataKinds
λ :set -XTypeApplications
λ getField #"getDims" $ moat (Foo (5,5) ['s'])
(5,5)
The Foo constructor should be hidden from clients. However, the field accessors for Foo should not be hidden; they must be in scope for the HasField instances of Moat to kick in.
Every function in your public-facing api should return and receive Moat Foos instead of Foos.
To make the accessor syntax slightly less verbose, we can turn to OverloadedLabels:
import GHC.OverloadedLabels
newtype Label r v = Label { field :: r -> v }
instance HasField l r v => IsLabel l (Label r v) where
fromLabel = Label (getField #l)
In ghci:
λ :set -XOverloadedLabels
λ field #getDims $ moat (Foo (5,5) ['s'])
(5,5)
Instead of hiding the Foo constructor, another option would be to make Foo completely public and define Moat inside your library, hiding any Moat constructors from clients.

Name conflicts in Haskell records

Haskell doesn't have dot notation for record members. For each record member a compiler creates a function with the same name with a type RecType -> FieldType. This leads to name conflicts. Are there any ways to work around this, i.e. how can I have several records with the same field names?
For large projects, I prefer to keep each type in its own module and use Haskell's module system to namespace accessors for each type.
For example, I might have some type A in module A:
-- A.hs
data A = A
{ field1 :: String
, field2 :: Double
}
... and another type B with similarly-named fields in module B:
-- B.hs
data B = B
{ field1 :: Char
, field2 :: Int
}
Then if I want to use both types in some other module C I can import them qualified to distinguish which accessor I mean:
-- C.hs
import A as A
import B as B
f :: A -> B -> (Double, Int)
f a b = (A.field2 a, B.field2 b)
Unfortunately, Haskell does not have a way to define multiple name-spaces within the same module, otherwise there would be no need to split each type in a separate module to do this.
Another way to avoid this problem is to use the lens package. It provides a makeFields template haskell function, which you can use like this:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeSynonymInstances #-}
import Control.Lens
data A = A
{ _aText :: String
}
makeFields ''A -- Creates a lens x for each record accessor with the name _aX
data B = B
{ _bText :: Int
, _bValue :: Int
}
-- Creates a lens x for each record accessor with the name _bX
makeFields ''B
main = do
let a = A "hello"
let b = B 42 1
-- (^.) is a function of lens which accesses a field (text) of some value (a)
putStrLn $ "Text of a: " ++ a ^. text
putStrLn $ "Text of b: " ++ show (b ^. text)
If you don't want to use TemplateHaskell and lens, you can also do manually what lens automates using TemplateHaskell:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeSynonymInstances #-}
data A = A
{ aText :: String
}
data B = B
{ bText :: Int
, bValue :: Int
}
-- A class for types a that have a "text" field of type t
class HasText a t | a -> t where
-- An accessor for the text value
text :: a -> t
-- Make our two types instances of those
instance HasText A String where text = aText
instance HasText B Int where text = bText
main = do
let a = A "hello"
let b = B 42 1
putStrLn $ "Text of a: " ++ text a
putStrLn $ "Text of b: " ++ show (text b)
But I can really recommend learning lens, as it also provides lots of other utilities, like modifying or setting a field.
The GHC developers developed a couple of extensions to help with this issue . Check out this ghc wiki page. Initially a single OverloadedRecordFields extension was planned, but instead two extensions were developed. The extensions are OverloadedLabels and DuplicateRecordFields. Also see that reddit discussion.
The DuplicateRecordFields extensions makes this code legal in a single module:
data Person = MkPerson { personId :: Int, name :: String }
data Address = MkAddress { personId :: Int, address :: String }
As of 2019, I'd say these two extensions didn't get the adoption I thought they would have (although they did get some adoption) and the status quo is probably still ongoing.

newtype Int -> CInt marshaller

I'm writing FFI to pdflib. Pdflib C API has lots of functions that return and/or take various handles (document, page, image, font) as plain Integer (not pointer).
In order to ensure i do not accidentally pass the wrong param to a function i create a bunch of newtypes in the form of:
newtype PdiDoc = PdiDoc Int
newtype PdiPage = PdiPage Int
newtype PdfImage = PdfImage Int
newtype PdfFont = PdfFont Int
Now i need to provide a marshaller for those types.
image2c (PdfImage i) = fromIntegral i
font2c (PdfFont f) = fromIntegral f
pdipage2c (PdiPage i) = fromIntegral i
As you see the marshallers are exactly the same, just for different types.
So my question is, is there some kind of type magic, SYB vodoo trick that i can use to have just one function to marshall all those types, or do i have to write same functions again and again for different newtypes ?
EDIT: I accepted Don's answer, because it solved my problem.
I switched on
GeneralizedNewtypeDeriving
added
deriving (Eq, Ord, Num, Enum, Real, Integral)
to each of my newtypes, and now i can use standard fromIntegral to marshall all of them.
Nathan Howell's answer is also correct one, i upvoted it. But unfortunately his solution would mean giving up on FFI preprocessors like c2hs i am using.
GHC's FFI extensions allow using newtypes that wrap FFI primitives. You could change the imported function signatures to use the newtypes and (hopefully) avoid having to unwrap them manually.
{-# LANGUAGE ForeignFunctionInterface #-}
module Main where
newtype Foo = Foo Int
foreign import ccall someCall :: Foo -> IO Foo
main :: IO ()
main = do
Foo x <- someCall (Foo 1)
print x
Alternatively, the new GHC Generics functionality (available since 7.2.1) allows generic unpacking and repacking of newtypes:
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE ForeignFunctionInterface #-}
{-# LANGUAGE TypeFamilies #-}
module Main where
import GHC.Generics
-- use a regular newtype
newtype Foo1 = Foo1 Int deriving (Generic, Show)
-- or with record syntax
newtype Foo2 = Foo2{foo2 :: Int} deriving (Generic, Show)
unpack :: (Generic a, Rep a ~ D1 dc (C1 cc (S1 sc (K1 R kc)))) => a -> kc
unpack = unK1 . unM1 . unM1 . unM1 . from
pack :: (Generic a, Rep a ~ D1 dc (C1 cc (S1 sc (K1 R kc)))) => kc -> a
pack = to . M1 . M1 . M1 . K1
-- the C import uses Ints
foreign import ccall "someCall" c'someCall :: Int -> IO Int
-- and the typed wrapper packs/unpacks to FFI primitives
someCall :: Foo1 -> IO Foo2
someCall = fmap pack . c'someCall . unpack
main :: IO ()
main = do
Foo2 x <- someCall (Foo1 1)
print x
You can derive 'Num' for your types using GeneralizedNewtypeDeriving, this helps you a bit with literals and operators.
For the marshalling, I'd use a FFI preprocess, such as hsc2hs, which can automate the wrapping and unwrapping of newtypes.
An example from RWH:

Resources