How can I deal with “typedef”-style data types with a minimum of boilerplate? - haskell

I defined a custom data type that contains a single field:
import Data.Set (Set)
data GraphEdge a = GraphEdge (Set a)
Defining my own type feels more semantically correct but it leads to a lot of boilerplate in my functions. Any time I want to use the built-in Set functions I have to unwrap the inner set and later rewrap it:
import Data.Set (map)
modifyItemsSomehow :: Ord a => GraphEdge a -> GraphEdge a
modifyItemsSomehow (GraphEdge items) = GraphEdge $ Set.map someFunction items
This could be improved slightly by making it a record, like
import Data.Set (Set, map)
data GraphEdge a = GraphEdge { unGraphEdge :: Set a }
modifyItemsSomehow = GraphEdge . map someFunction . unGraphEdge
but this still feels far from ideal. What is the most idiomatic way to handle this kind of boilerplate when dealing with a user-defined data type that consists of a single field?

Before anything else, you should make sure to use newtype for single-field single-constructor types. data introduces runtime overhead and extra laziness, and prevents us from using the first two of the following techniques.
First, you can use GeneralizedNewtypeDeriving when possible:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype Foo a = Foo a deriving (Eq, Show, Ord, Num)
foo :: Foo Int
foo = 0
bar :: Foo Int
bar = foo * 120
Second, you can use coerce to generally convert between newtype wrappings:
import Data.Coerce
newtype Foo a = Foo a
newtype Bar a = Bar a
a :: [(Foo (Bar Int), Foo ())]
a = [(Foo (Bar 0), Foo ())]
b :: [(Int, ())]
b = coerce a
Third, you can use iso-s from lens to concisely move operations over/under newtype constructors.
{-# LANGUAGE TemplateHaskell #-}
import Data.Set (Set)
import qualified Data.Set as Set
import Control.Lens
newtype GraphEdge a = GraphEdge (Set a)
makePrisms ''GraphEdge
modifyItemsSomehow :: Ord a => GraphEdge a -> GraphEdge a
modifyItemsSomehow = _GraphEdge %~ Set.map someFunction

Related

Polymorphic lens without template 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)

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.

How to Define Typeclass Synonyms

In an attempt to make a sane(r) alternative to Haskell's numeric type system, the devs of numeric-prelude slipped up and decided to name all of their type classes C. Aside from making the docs totally confusing, this means that I have to fully qualify all uses of the typeclasses:
import qualified Algebra.Additive (C)
import qualified Algebra.Ring (C)
...
newtype Foo a = Foo a
instance (Algebra.Additive.C a) => Algebra.Additive.C (Foo a) where ...
myadd :: (Algebra.Additive.C a) => a -> a -> a
myadd a b = ...
Also, since NumericPrelude has finer grained typeclasses, I usually have to import several different NumericPrelude modules. I can simplify this a little by defining top-level constraint synonyms:
{-# LANGUAGE ConstraintKinds #-}
module NPSynonyms (Additive) where
import qualified Algebra.Additive (C)
type Additive a = (Algebra.Additive.C a)
which allows me to make sane functions:
myadd :: (Additive a) => a -> a -> a
myadd a b = ...
However, when I need to define an instance, I still have to (also) import the original NumericPrelude class:
{-# LANGUAGE ConstraintKinds #-}
import NPSynonyms
import Algebra.Additive (C)
newtype Foo a = Foo a
instance (Additive a) => Algebra.Additive.C (Foo a) where ...
So instead of making Additive a type synonym with kind Constraint, what I'd really like is to define a typeclass synonym for the typeclass Algebra.Additive.C. Is there any way to do this in GHC 7.8, or is there any sane alternative?
you have to fully qualify
No, not fully qualify. Consider:
import qualified Algebra.Additive as Add
myadd :: Add.C a => a -> a -> a
That looks fairly readable to me.
EDIT:
Also consider making a superclass and treating that as an alias:
class (Add.C a, Ring.C a) => Num a where
instance Num Int
instance Num Word

How to apply a polymorphic function to a Dynamic value

Is there a sane way to apply a polymorphic function to a value of type Dynamic?
For instance, I have a value of type Dynamic and I want to apply Just to the value inside the Dynamic. So if the value was constructed by toDyn True I want the result to be toDyn (Just True). The number of different types that can occur inside the Dynamic is not bounded.
(I have a solution when the types involved come from a closed universe, but it's unpleasant.)
This is perhaps not the sanest approach, but we can abuse my reflection package to lie about a TypeRep.
{-# LANGUAGE Rank2Types, FlexibleContexts, ScopedTypeVariables #-}
import Data.Dynamic
import Data.Proxy
import Data.Reflection
import GHC.Prim (Any)
import Unsafe.Coerce
newtype WithRep s a = WithRep { withRep :: a }
instance Reifies s TypeRep => Typeable (WithRep s a) where
typeOf s = reflect (Proxy :: Proxy s)
Given that we can now peek at the TypeRep of our Dynamic argument and instantiate our Dynamic function appropriately.
apD :: forall f. Typeable1 f => (forall a. a -> f a) -> Dynamic -> Dynamic
apD f a = dynApp df a
where t = dynTypeRep a
df = reify (mkFunTy t (typeOf1 (undefined :: f ()) `mkAppTy` t)) $
\(_ :: Proxy s) -> toDyn (WithRep f :: WithRep s (() -> f ()))
It could be a lot easier if base just supplied something like apD for us, but that requires a rank 2 type, and Typeable/Dynamic manage to avoid them, even if Data does not.
Another path would be to just exploit the implementation of Dynamic:
data Dynamic = Dynamic TypeRep Any
and unsafeCoerce to your own Dynamic' data type, do what you need to do with the TypeRep in the internals, and after applying your function, unsafeCoerce everything back.

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