How can I deal with typedef data types with a minimal template?

I defined a custom data type that contains one field:

import Data.Set (Set) data GraphEdge a = GraphEdge (Set a) 

Defining my own type seems more semantically correct, but it leads to a lot of patterns in my functions. Every time I want to use the built-in functions of Set , I have to expand the internal set and then overwrite it:

 import Data.Set (map) modifyItemsSomehow :: Ord a => GraphEdge a -> GraphEdge a modifyItemsSomehow (GraphEdge items) = GraphEdge $ Set.map someFunction items 

This could be slightly improved by recording, for example

 import Data.Set (Set, map) data GraphEdge a = GraphEdge { unGraphEdge :: Set a } modifyItemsSomehow = GraphEdge . map someFunction . unGraphEdge 

but it still seems far from ideal. What is the most idiomatic way to handle this type of template when working with a user data type consisting of a single field?

+6
source share
1 answer

First of all, you should use newtype for single-user single-line types. data introduces runtime overhead and extra laziness and does not allow us to use the first two of the following methods.

First, you can use GeneralizedNewtypeDeriving , if possible:

 {-# LANGUAGE GeneralizedNewtypeDeriving #-} newtype Foo a = Foo a deriving (Eq, Show, Ord, Num) foo :: Foo Int foo = 0 bar :: Foo Int bar = foo * 120 

Secondly, you can use coerce to convert between newtype covers:

 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 briefly translate operations on / under newtype constructs.

 {-# 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 
+5
source

All Articles