"Extending" an interface to allow for optional usage of function in instances - haskell

I am trying to add optional spacing into generated source code, the source code is generated into several languages like Python and Java.
I have an abstract file (non final code language specific) I have a function for creating the "if" control statement. It is similar to:
ifConditions :: (RendererSym r) => (Doc -> Doc) -> Doc -> Doc -> Doc -> [(SyValue r, MBody r)] -> MBody r -> MStatement r
ifConditions a startIf c d (x:xs) z = .....
That part is not too important here other than in the body of this function there is something like
<+> startIf which I want to turn into <> optionalSpace startIf
No I could have instead simply changed <+> startIf to <> startIf and gone into each language specific file and changed the following
instance ControlStatements JavaGenCode where
ifConditions = G.ifConditions a startIf b c
into the following if I wanted a space. prepSpace could be imported from an "abstract" file into each language specific rendering file as needed.
prepSpace :: Doc -> Doc
prepSpace x = space <> x
instance ControlStatements JavaGenCode where
ifConditions = K.ifConditions a (prepSpace startIf) b c
Instead is it possible (a good idea) to add this to the ControlStatements class?
class (BSym r, VSym r) => ControlStatements r where
ifConditions :: [(SyValue r, MBody r)] -> MBody r -> MStatement r
optionalSpace :: Label -> MStatement r
Then in each language specific rendering file:
instance ControlStatements JavaGenCode where
ifConditions = K.ifConditions a startIf b c --same as before
optionalSpace = K.optSpace Empty
and in K file:
optionalSpace :: (RendererSym r) => Label -> MStatement r
optionalSpace n = ...
My main confusion is tying it all back into ifConditions. Now that
I have optionalSpace in the ControlStatements class
I have an instance in instance ControlStatements JavaGenCode, as needed
optionalSpace is defined in K
How can I tie this back into the ifConditions function, so that I can use <> optionalSpace startIf? What am I overlooking here?

There's a lot of missing context (why is optionalSpace :: Label -> MStatement r being used like it's Doc -> Doc (in <> optionalSpace startIf)? Why is ifConditions a method if you're always going to implement it using K.ifConditions? ...)
A shot in the dark.
Try defining a wrapper around K.ifConditions in the file containing the ControlStatements class,
class ControlStatements r where
ifConditions :: ...
optionalSpace :: ...
kifConditions :: ControlStatements r => ...
kifConditions a startIf b c = K.ifConditions a (optionalSpace startIf) b c

Related

Using Haskell Graphviz Library

If I have a DotNode with an UnknownAttribute called "consumes", how do I access it later to get the value of "consumes" that was set earlier on when constructing the graph?
I've tried going through the source code to find getter functions, but haven't found any.
Update : The following code works as a way to access the attributes.
consumes :: Attributes -> [TL.Text]
consumes = foldl f []
where
f b a = case a of
UnkownAttribute "consumes" t -> b <> TL.words t
_ -> b <> []
which can be called by:
consumes (nodeAttributes n)
You can use the functions:
nodeAttributes :: DotNode -> [Attribute]
isSpecifiedCustom :: Text -> Attribute -> Bool
customValue :: Attribute -> Text
You can combine them as follows:
getConsumes :: DotNode -> [Text]
getConsumes n =
map customValue
(filter (isSpecifiedCustom "consumes")
(nodeAttributes n))
You might want to consider what should happen if there are multiple "consumes" attributes on the same node. I've chosen to just return all values.

How to use the same record selector two ways within a function? Lenses?

I have some data that have different representations based on a type parameter, a la Sandy Maguire's Higher Kinded Data. Here are two examples:
wholeMyData :: MyData Z
wholeMyData = MyData 1 'w'
deltaMyData :: MyData Delta
deltaMyData = MyData Nothing (Just $ Left 'b')
I give some of the implementation details below, but first the actual question.
I often want to get a field of the data, usually via a local definition like:
let x = either (Just . Left . myDataChar) myDataChar -- myDataChar a record of MyData
It happens so often I would like to make a standard combinator,
getSubDelta :: ( _ -> _ ) -> Either a b -> Maybe (Either c d)
getSubDelta f = either (Just . Left . f) f
but filling in that signature is problematic. The easy solution is to just supply the record selector function twice,
getSubDelta :: (a->c) -> (b->d) -> Either a b -> Maybe (Either c d)
getSubDelta f g = either (Just . Left . f) g
but that is unseemly. So my question. Is there a way I can fill in the signature above? I'm assuming there is probably a lens based solution, what would that look like? Would it help with deeply nested data? I can't rely on the data types always being single constructor, so prisms? Traversals? My lens game is weak, so I was hoping to get some advice before I proceed.
Thanks!
Some background. I defined a generic method of performing "deltas", via a mix of GHC.Generics and type families. The gist is to use a type family in the definition of the data type. Then, depending how the type is parameterized, the records will either represent whole data or a change to existing data.
For instance, I define the business data using DeltaPoints.
MyData f = MyData { myDataInt :: DeltaPoint f Int
, myDataChar :: DeltaPoint f Char} deriving Generic
The DeltaPoints are implemented in the library, and have different forms for Delta and Z states.
data DeltaState = Z | Delta deriving (Show,Eq,Read)
type family DeltaPoint (st :: DeltaState) a where
DeltaPoint Z a = a
DeltaPoint Delta a = Maybe (Either a (DeltaOf a))
So a DeltaPoint Z a is just the original data, a, and a DeltaPoint Delta a, may or may not be present, and if it is present will either be a replacement of the original (Left) or an update (DeltaOf a).
The runtime delta functionality is encapsulated in a type class.
class HasDelta a where
type DeltaOf a
delta :: a -> a -> Maybe (Either a (DeltaOf a))
applyDeltaOf :: a -> DeltaOf a -> Maybe a
And with the use of Generics, I can usually get the delta capabilities with something like:
instance HasDelta (MyData Z) where
type (DeltaOf (MyData Z)) = MyData Delta
I think you probably want:
{-# LANGUAGE RankNTypes #-}
getSubDelta :: (forall f . (dat f -> DeltaPoint f fld))
-> Either (dat Z) (dat Delta)
-> Maybe (Either (DeltaPoint Z fld) (DeltaOf fld))
getSubDelta sel = either (Just . Left . sel) sel
giving:
x :: Either (MyData Z) (MyData Delta)
-> Maybe (Either (DeltaPoint Z Char) (DeltaOf Char))
x = getSubDelta myDataChar
-- same as: x = either (Just . Left . myDataChar) myDataChar

Pattern Matching with Types in Haskell

Say I have a type that contains coordinates of various objects defined as:
type Point = (Int, Int)
data Object = A Point
| B Point
| C Point
I want to create a function that would check for overlap of objects, like so
checkOverlap:: Object -> Point -> Bool
I want to define just one function that would work for all objects, without having to specify "checkOverlap (A point) (x,y)", "checkOverlap (B point) (x,y)" and so on.
I've googled the problem but the only solution I was able to find is to add an intermediate type that would gather all of the different objects so that you can pattern match on that type. However since this is a homework exercise, I'm not allowed to modify large chunks of code to accommodate this new type.
Is there any other way? Maybe not even with pattern matching. It just seems like bad programming having to copy the same function multiple times.
You can use record syntax if you're allowed to change the definition of Object:
type Point = (Int, Int)
data Object = A { getPoint :: Point, ... }
| B { getPoint :: Point, ... }
| C { getPoint :: Point, ... }
checkOverlap :: Object -> Point -> Bool
checkOverlap obj pt = doSomething (getPoint obj) pt
If you're not allowed to change the definition and the extraction of points is a common task, you could simply add getPoint as an addtional function. You can use case for this if you don't want to write getPoint several times:
getPoint :: Object -> Point
getPoint obj = case obj of
A pt -> pt
B pt -> pt
C pt -> pt
If you don't want an additional function, but still want only one version of checkOverlap, you can move the case into checkOverlap:
checkOverlap :: Object -> Point -> Bool
checkOverlap obj pt = let opt = case obj of {A a -> a; B b -> b; C c -> c}
in -- use opt and pt
Consider changing your object type definition:
data ObjTy = A | B | C
data Object = Obj ObjTy Point
checkOverlap:: Object -> Point -> Bool
checkOverlap (Obj _ (x,y)) (u,v) = ...
As in my comment, here's a way with typeclasses:
type Point = (Int, Int)
data Obj = A Point | B Point | C Point
class HasPoint p where
point :: p -> Point
instance HasPoint (Obj) where
point (A p) = p
point (B p) = p
point (C p) = p
checkOverlap :: (HasPoint ob) => ob -> Point -> Bool
checkOverlap ob otherPoint =
undefined
where
myPoint = point ob
somethingA = checkOverlap (A (1,1)) (1,1)
somethingB = checkOverlap (B (1,1)) (1,1)

Are there any useful abstractions for Haskell's record syntax?

To try and simplify this problem I have defined these arrow functions:
splitA :: (Arrow arr) => arr a b -> arr a (b,a)
splitA ar = ar &&& (arr (\a -> id a))
recordArrow
:: (Arrow arr)
=> (d -> r)
-> (d -> r -> d)
-> (r -> r)
-> arr d d
recordArrow g s f = splitA (arr g >>^ f) >>^ \(r,d) -> s d r
Which then let's me do something like this:
unarrow :: ((->) b c) -> (b -> c) -- unneeded as pointed out to me in the comments
unarrow g = g
data Testdata = Testdata { record1::Int,record2::Int,record3::Int }
testRecord = unarrow $
recordArrow record1 (\d r -> d { record1 = r }) id
>>> recordArrow record2 (\d r -> d { record2 = r }) id
>>> recordArrow record3 (\d r -> d { record3 = r }) id
As you can see this doesn't make very good use of DRY.
I'm hoping there might be some sort of language extension that could help simplify this process. So that the above could simply be re-written as:
testRecord' = unarrow $
recordArrow' record1 id
>>> recordArrow' record2 id
>>> recordArrow' record3 id
Updated for clarity: To clarify a little bit. I'm aware that I could do something like this:
foo d = d { record1 = id (record1 d), record2 = id (record2 d) }
But this ignores any execution order and any state. Suppose the update function for record2 relies on the updated value for record1. Or alternatively, I may want to create a different arrow that looks like this: arr d (d,x) and then I want to build a list of [x] the order of which depends on the evaluation order of the records.
What I've found is that I frequently want to execute some functionality and afterwards update a record. I can do that by threading the state like this
g :: d -> r -> d
foo d = let d' = d { record1 = (g d) (record1 d) } in d' { record2 = (g d') (record2 d') }
But I think arrow notation is neater, and I could also have [arr d d] and chain them together in a sequence. Plus if r or d are Monads it creates neater code. Or if they're both Monads, it let's me perform layered binds without having to use a Monad Transformer. In the case of ST s x it let's me thread the state s around in an ordered way.
I'm not trying to solve one particular problem. I'm just trying to find an abstracted method of updating a record syntax without having to explicitly define some sort of "getter" and "setter".
Below was answered in the comments--
Sidenote: I've had to define a function unarrow for converting a function (->) arrow back to a function. Otherwise if I have someArrow b for an arrow arr b c I can't get to value c. With the unarrow function I can write unarrow someArrow b and it works fine. I feel like I must be doing something wrong here because my definition for unarrow is simply unarrow g = g.
The abstraction you are looking for is called a lens and the lens package on Hackage is probably the most widespread implementation of the idea currently in use. Using the lens package you can define your recordArrow' as
{-# LANGUAGE RankNTypes #-}
import Control.Arrow
import Control.Lens
recordArrow' :: Arrow arr => Lens' d r -> (r -> r) -> arr d d
recordArrow' field f = arr $ field %~ f
The %~ is an update operator which updates a values inside a larger data structures using a function via the given lens.
Now the problem is that you don't automatically get lenses for your record fields, but you can either manually define them or generate them automatically using Template Haskell. For example
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data Testdata = Testdata { _record1::Int, _record2::Int, _record3::Int }
makeLenses ''Testdata
Note that the original record accessors are prefixed with underscores so that we can use the original names for the lenses.
testRecord :: Testdata -> Testdata
testRecord =
recordArrow' record1 id
>>> recordArrow' record2 id
>>> recordArrow' record3 id
The unarrow function is not needed. It's better to force a generic type to a concrete type by simple giving a type signature.
Note that if you are just looking for a nicer syntax to chain record operations and don't have any other use for arrows, you might prefer just to use the State monad with lenses. For example:
import Control.Monad.State (execState)
testRecord' :: Testdata -> Testdata
testRecord' = execState $ do
record1 .= 3
record2 %= (+5)
record3 += 2

Different setter and getter types in Haskell's lenses

I've got a data type G, which have got field _repr :: Data.Graph.Inductive.Gr String String. The normal way, when adding new node into Gr graph, we have to provide an LNode a object, which basically is defined as a tuple of (Int, a), where Int is the nodes index in Graph - see the example function add below.
I want to implement a function addx, which will compute the index automatically (for example by using Data.Graph.Inductive.newNodes function). I want the addx to have signature of addx :: String -> G -> Int and this function will compute new free index, modify the graph G and return this computed index. Is it possible in Haskell to create such function (which will modify an existing object - G in this case) - by using lenses or something like that?
I have seen, that Haskell lens is defined like lens :: (a -> c) -> (a -> d -> b) -> Lens a b c d and lens is basically a "getter" and "setter", so its signature allows for different types of getter output (c), setter value (d) and setter output (b).
import qualified Data.Graph.Inductive as DG
data G = G { _repr :: DG.Gr String String, _name::String} deriving ( Show )
empty :: G
empty = G DG.empty ""
add :: DG.LNode String -> G -> G
add node g = g{_repr = DG.insNode node $ _repr g}
-- is it possible to define it?
addx :: String -> G -> Int
addx name g = undefined
main :: IO ()
main = do
let g = add (1, "test2")
$ add (0, "test1")
$ empty
n1 = addx "test2" g
g2 = DG.insEdge(n1,0)
$ DG.insEdge(0,1)
print $ g
Your type for addx is broken since you can't modify G in a pure function without returning the modified form like addx1 :: String -> G -> (Int, G). If you have a clever eye for Haskell monads, you might notice that this has an isomorphic type, addx2 :: String -> State G Int.
We can align everything to this "stateful" orientation
add' node = do g <- get
put $ g { _repr = DB.insNode node $ _repr g }
and make it more succinct with lenses
add'' node = repr %= DB.insNode node
The real challenge here is, at the end of the day, tracking the node identity. One way would be to carry it alongside the repr in your type
data G = G { _repr :: DG.Gr String String, _name :: String, _index :: Int }
empty = G DG.empty "" 0
then use that when building nodes (using lenses again!)
addx' name = do i <- use index
repr %= DB.insNode (i, node)
i += 1

Resources