I am still a newbie to Haskell and I think I am over my head right now. I have code that looks like the following.
data World = World {
intStack :: [Int],
boolStack :: [Bool]
} deriving Show
instance IntStack World where
getIntStack = intStack
putIntStack ints (World _ bools) = World ints bools
instance BoolStack World where
getBoolStack = boolStack
putBoolStack bools (World ints _) = World ints bools
class IntStack a where
getIntStack :: a -> [Int]
putIntStack :: [Int] -> a -> a
class BoolStack a where
getBoolStack :: a -> [Bool]
putBoolStack :: [Bool] -> a -> a
(<=>) :: (IntStack c, BoolStack c) => c -> c
(<=>) w = putIntStack xs . putBoolStack ((x == x'):bs) $ w
where (x:x':xs) = getIntStack w
bs = getBoolStack w
(<+>) :: (IntStack c) => c -> c
(<+>) w = putIntStack ((x+x'):xs) w
where (x:x':xs) = getIntStack w
My focus (For now ignoring error cases in the functions) is being able to chain together functions like (<=>) and (<+>) assuming that the underlying data type implements the function's required interfaces.
I feel like I can clean this up a lot with a state monad, but I am not sure how to structure it to allow changes to whatever data type that implements IntStack, BoolStack, etc..
I know that this is a horribly vague description, but I feel like the code I have above is probably the absolutely wrong way to go about it.
Thanks for any feedback!
class IntStack a where
getIntStack :: a -> [Int]
putIntStack :: [Int] -> a -> a
class BoolStack a where
getBoolStack :: a -> [Bool]
putBoolStack :: [Bool] -> a -> a
Congratulations, you've just invented lenses! Abstract the [Int]
and [Bool]
types, and use data
instead of class
, and you get something like
data Lens a b = Lens
{ get :: a -> b
, put :: b -> a -> a
}
...which is implemented in half a dozen packages on Hackage. Most offer at least:
getIntStack
/putIntStack
and getBoolStack
/putBoolStack
directly from a data declarationWorld
out of some larger structure, then picking the intStack
out of the World
) and vertical composition (running two lenses in parallel, each on one side of a pair)State
and StateT
(e.g. something of type Lens a b -> State b r -> State a r
), which would let you write computations on a [Bool]
or [Int]
and run them as if they were computations on a World
So, check out hackage! There's the data-lens
family, which includes a core, the deriving ability, and the stateful interface; the lens package; and the pointless-lenses package. There are probably some I forgot, too.