How should I organize normal and "state" versions of functions in the state monad? - haskell

I decided to try the State Monad to try and clean up some of the projects that I've started. I ran into a naming/compartmentalization problem.
If I have the following objects:
data Obj = Player { oPos :: Point }
data World = World { wKeys :: [Key], wPlayer :: Obj }
I might have a convenience function like:
setPlayer :: Obj -> World -> World
setPlayer o w = w{wPlayer = o}
and a matching state operation like:
setPlayerW :: Obj -> WorldState ()
setPlayerW o = get >>= put . setPlayer o
which uses the other convenience function; for convenience.
What is the typical naming convention for something like this? I post-pended the state version with a W, but that's kind of ugly.
And are the "state-versions" typical segregated from the "object-versions" in a separate file?
Am I going about this wrong completely? Is there a better set-up then having 2 different versions of any operations I might need?

Personally, I wouldn't have a separate function for the state version myself. Instead, use the modify function instead:
do let o = player
modify (setPlayer o)
something else
In a sense, the naming convention you're looking for would just be the same as using modify except folded into the names of each function. When I find myself naming functions like this, I generally try to find some way to organize them in the language instead of using their names. Sometimes, like here, an existing function is all you need; other times, it involves creating a function of your own to achieve the same end or extracting things into a module.
The core idea is that it's better to reify patterns in your code using first-class language constructs instead of encoding them indirectly into the names. (Of course, if this ends up really awkward, you shouldn't do it, but it's fine here.)

This looks like a good time to introduce the lens library. This is a bit of a daunting library at first, and I still struggle with some of its more complex features (the rabbit hole is pretty deep for this one), but it can really simplify a lot of your State code. To use it, it's recommended to change your data types a bit first so you can utilize template haskell:
import Control.Monad
import Control.Monad.State
import Control.Lens
-- Made assumption on what Point would look like
data Point = Point { _x :: Int, _y :: Int } deriving (Eq, Show)
data Obj = Player { _oPos :: Point } deriving (Eq, Show)
data World = World { _wKeys :: [Key], _wPlayer :: Obj } deriving (Eq, Show)
makeLenses ''Point
makeLenses ''Obj
makeLenses ''World
-- Also assumed this type
type WorldState = StateT World IO
Then you can write code that looks very much imperative using the generated lenses
setPlayerW :: Obj -> WorldState ()
setPlayerW o = wPlayer .= o
Or if you want the non-monadic version
setPlayer :: Obj -> World -> World
setPlayer o = wPlayer .~ o
So this uses the .= operator to set the wPlayer field of the World state to the new value. More impressively, you could use it to write code like
moveUp, moveDown, moveLeft, moveRight :: WorldState ()
moveUp = wPlayer.oPos.y += 1
moveDown = wPlayer.oPos.y -= 1
moveLeft = wPlayer.oPos.x -= 1
moveRight = wPlayer.oPos.x += 1
Which makes it look a lot like an object oriented language using normal function composition. A quick test:
game :: WorldState ()
game = do
replicateM_ 3 moveUp
replicateM_ 5 moveLeft
replicateM_ 10 moveRight
replicateM_ 6 moveDown
> execStateT game $ World [] $ Player $ Point 0 0
World {_wKeys = [], _wPlayer = Player {_oPos = Point {_x = 5, _y = -3}}}
There are a lot of really interesting and useful operators in the lens library, and there's a lot of support built-in for using it with StateT stacks.
Another nice feature is the zoom function, which takes a lens and "zooms in" on it, letting you operate as if your state has the value of whatever you zoomed onto. An example would be
game = zoom (wPlayer.oPos) $ do
y += 3
x -= 5
x += 10
y -= 6
And this would produce the same result as before. This is generally more efficient (fewer layers to unwrap at each step) and can be much cleaner.

Related

How to avoid default return value when accessing a non-existent field with lenses?

I love Lens library and I love how it works, but sometimes it introduces so many problems, that I regret I ever started using it. Lets look at this simple example:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data Data = A { _x :: String, _y :: String }
| B { _x :: String }
makeLenses ''Data
main = do
let b = B "x"
print $ view y b
it outputs:
""
And now imagine - we've got a datatype and we refactor it - by changing some names. Instead of getting error (in runtime, like with normal accessors) that this name does not longer apply to particular data constructor, lenses use mempty from Monoid to create default object, so we get strange results instead of error. Debugging something like this is almost impossible.
Is there any way to fix this behaviour? I know there are some special operators to get the behaviour I want, but all "normal" looking functions from lenses are just horrible. Should I just override them with my custom module or is there any nicer method?
As a sidenote: I want to be able to read and set the arguments using lens syntax, but just remove the behaviour of automatic result creating when field is missing.
It sounds like you just want to recover the exception behavior. I vaguely recall that this is how view once worked. If so, I expect a reasonable choice was made with the change.
Normally I end up working with (^?) in the cases you are talking about:
> b ^? y
Nothing
If you want the exception behavior you can use ^?!
> b ^?! y
"*** Exception: (^?!): empty Fold
I prefer to use ^? to avoid partial functions and exceptions, similar to how it is commonly advised to stay away from head, last, !! and other partial functions.
Yes, I too have found it a bit odd that view works for Traversals by concatenating the targets. I think this is because of the instance Monoid m => Applicative (Const m). You can write your own view equivalent that doesn't have this behaviour by writing your own Const equivalent that doesn't have this instance.
Perhaps one workaround would be to provide a type signature for y, so know know exactly what it is. If you had this then your "pathological" use of view wouldn't compile.
data Data = A { _x :: String, _y' :: String }
| B { _x :: String }
makeLenses ''Data
y :: Lens' Data String
y = y'
You can do this by defining your own view1 operator. It doesn't exist in the lens package, but it's easy to define locally.
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data Data = A { _x :: String, _y :: String }
| B { _x :: String }
makeLenses ''Data
newtype Get a b = Get { unGet :: a }
instance Functor (Get a) where
fmap _ (Get x) = Get x
view1 :: LensLike' (Get a) s a -> s -> a
view1 l = unGet . l Get
works :: Data -> String
works = view1 x
-- fails :: Data -> String
-- fails = view1 y
-- Bug.hs:23:15:
-- No instance for (Control.Applicative.Applicative (Get String))
-- arising from a use of ‘y’

How to read settings and geometric shapes from a file in Haskell for later use, with operations in between?

I can write simple algorithms in Haskell, and even successfully coded a very simple graphics raytracer (spheres, planes, rectangles) as a learning tool (I wrote a more complex one in C++, for an online course). All settings for this raytracer were hardcoded as constants, be it the desired image width/height, camera position, ambient light intensity, etc. Example:
imageWidth = 1600
imageHeight = 900
bgColor = Color 0 0 0
maxDepth = 5
ambientIntensity = Color 0 0 0
However, as soon as I tried to extend the raytracer to read these settings and the scene itself (positions of objects, lights, etc) from a file, I hit a brick wall. Example scene file:
size 1600 900
output generated_image.png
ambient 0.1 0.1 0.1
triangle 0.5 1.4 2.8
triangle 0.5 2.4 3.8
sphere -5.5 -5.5 0 4
sphere +5.5 +5.5 0 4
Important: The scene file additionally includes matrix operations (translate, rotate, etc), which I should store in a stack as I read the file, as well as material definitions for the objects. If I read a sphere in a certain line, that sphere should use the material and matrix transformation that are set as of that line. Then, some more matrix transformations and material settings may or may not follow before reading another object (sphere, triangle, etc), and so on.
It seems to me that this task involves some severe data mutation. Due to Haskell's pure nature and my limited knowledge, I'm having problems with IO types and how to proceed in general, and my Internet research honestly didn't help a lot.
I know how to read the scene file using readFile, get each line using lines, separate parameters using words and even convert those to Ints/Floats as needed using read. I believe I should apply a function to each line, probably using mapM or mapM_, which should detect the used command (size, ambient, sphere, etc), and act as needed. But actions are very different for each command. While "size" only requires that I save the image width and height in values, "sphere" would require that I read values, use the currently active matrix transformation, currently active material and then store it in a list somewhere. I can't read everything and then act, or I would have to also store the order of operations and the problem would be the same... But, even in the simpler "size" case, I'm clueless about how to do this, as these are all operations that involve mutation.
Concretely:
How should I go about binding a value read from a file to a name, in order to use it later? Ex.: imageWidth and imageHeight. With only one setting in the file, I could do this by simply returning the read value from the reader function. This is not the case...
Should I create a new data type named "Scene" with named parameters (they are many), which contains all the settings to later use in the raytracer? This is how I would do it in C++, but here it pollutes the function namespace (if that is how I should call it) with all the arguments.
How could I achieve this mutation of values? I'm assuming I need pointers or some impure Haskell functionality, and I believe only this initial setup would require such things. Later on, when the image is generated, I should be able to access the stored values as usual, using pure functions. Is this possible? None of the settings read from the file are supposed to change in runtime, but they involve "mutation" of data while reading, especially in the case of materials, the stack of matrix transformations and even adding to the list of objects.
I apologize for the long question. I realize it is also rather abstract and hasn't got a "code solution". If my questions are too broad, could you recommend a resource where such a problem is tackled in a clear way? I'm feeling that I also need to learn quite a lot about Haskell before achieving this.
Many thanks.
It seems now this question is simply about parsing your particular file format. So I will show you how to use a commonly used parsing library, Parsec, to do it. If you are not familiar with parsec and applicative style parsing, please read the section in RWH. This will essentially be a fully featured parser, so it is quite long.
I will repeat it once more: using mutation to do this in Haskell is simply wrong. Only a masochist would even attempt it. Please push all ideas of mutation out of your mind.
First, write datatypes to represent everything:
type Point3D = (Float, Float, Float)
data SceneObject
= Sphere Point3D Float
| Triangle Point3D Point3D Point3D
deriving Show
data SceneTransform
= Translate Float Float Float
| Rotate Float Float Float
deriving Show
Notice we seperate things into transformations and objects. The distinction, in general, is that transformations are things which can be applied to objects. Then, the entire scene:
data SceneConfig x = SceneConfig
{ sc_height :: Int
, sc_width :: Int
, sc_out :: FilePath
, sc_objs :: x
} deriving Show
Notice the objects are a parameter. This is because we will first parse the data exactly as it is found in the file, then write a function which will transform the data to a more convenient format. We will not do something absurd like trying to parse files and transform the parsed data simultaneously.
{-# LANGUAGE RecordWildCards, NamedFieldPuns #-}
import Text.Parsec hiding ((<|>))
import Text.ParserCombinators.Parsec.Number
import Control.Applicative hiding (many)
type Parser = Parsec String ()
parseFloat :: Parser Float
parseFloat = spaces >> (sign <*> (either fromInteger id <$> decimalFloat))
parsePoint3D :: Parser Point3D
parsePoint3D = spaces >> ((,,) <$> parseFloat <*> parseFloat <*> parseFloat)
These are helper functions for parsing basic things. We parse points as floats separated by whitespace.
parseTranslate =
string "translate" >> Translate <$> parseFloat <*> parseFloat <*> parseFloat
The above is quite simple: a translate object is the string "Translate" followed by three floats.
The other possible objects look pretty much exactly the same:
parseRotate =
string "rotate" >> Rotate <$> parseFloat <*> parseFloat <*> parseFloat
parseSphere =
string "sphere" >> Sphere <$> parsePoint3D <*> parseFloat
parseTriangle =
string "triangle" >> Triangle <$> parsePoint3D <*> parsePoint3D <*> parsePoint3D
We need a parser which parses any of these. choice takes a list of parsers and succeeds on the first one of them which succeeds:
parseObjOrTransform :: Parser (Either SceneObject SceneTransform)
parseObjOrTransform = choice $ map try $
[ Left <$> parseSphere
, Left <$> parseTriangle
, Right <$> parseRotate
, Right <$> parseTranslate
]
Now we are ready to parse the entire config:
parseSceneConfigWith :: Parser x -> Parser (SceneConfig x)
parseSceneConfigWith p = do
string "size"
sc_height <- spaces >> int
sc_width <- spaces >> int
char '\n'
string "output"
sc_out <- spaces >> many1 (noneOf "\n\t\"<>|/\\?*: ")
char '\n'
sc_objs <- p
return $ SceneConfig { .. }
This requires that "size" and "output" are placed in the correct order. You can, of course, change this; but this way is the simplest.
Now we parse the data including objects and transformations - but again, we do not do computation on them while parsing:
parseSceneRaw :: Parser (SceneConfig [Either SceneObject SceneTransform])
parseSceneRaw = parseSceneConfigWith (sepEndBy parseObjOrTransform (char '\n'))
Now we are ready to apply transforms to objects:
appTr :: SceneTransform -> SceneObject -> SceneObject
appTr (Translate dx dy dz) obj =
case obj of
(Sphere p0 r) -> Sphere (dp ~+~ p0) r
(Triangle p0 p1 p2) -> Triangle (dp ~+~ p0) (dp ~+~ p1) (dp ~+~ p2)
where dp = (dx, dy, dz)
appTr _ _ = error "TODO"
applyTransforms :: [Either SceneObject SceneTransform] -> [SceneObject]
applyTransforms [] = []
applyTransforms (Left obj : xs) = obj : applyTransforms xs
applyTransforms (Right tf : xs) = applyTransforms (map f xs) where
f (Left obj) = Left $ appTr tf obj
f x = x
The logic of this function is fairly simple. It applies each transform it encounters to every subsequent object. You could do this with a matrix stack, but it is overkill, at least for the subset of your datatype I have implemented.
Then, for convenience, we can write a parser which performs parseSceneRaw, then applies the transforms:
parseScene :: Parser (SceneConfig [SceneObject])
parseScene = do
SceneConfig { sc_objs, .. } <- parseSceneRaw
return $ SceneConfig { sc_objs = applyTransforms sc_objs, .. }
Then a simple test case:
testFile :: String
testFile = unlines
["size 1600 900"
,"output generated_image.png"
,"translate 0 1 0"
,"triangle 0.5 1.4 2.8 4.5 2.3 3.1 9.6 1.4 0.0"
,"translate 10 10 10"
,"sphere -5.5 -5.5 0 4"
,"translate -100 -100 -100"
,"sphere 5.5 5.5 0 4"
]
testMain = print (parse parseSceneRaw "" testFile) >>
print (parse parseScene "" testFile)
If you are willing to change your file format, one low-effort option would be to create a data structure for the commands, that implements Show and Read. Then you can use these to read the data structure from disk all at once, and to write it out again if need be.
For instance, I have a program with the following data structure declared below. The SoundMap contains within it a list of SoundSets, and those SoundSets may each be one of the three types. In your case you'd have a list of Commands of various types.
data SoundSet =
Synth {
syn_name :: String,
syn_keytype :: KeyType } |
NoteWavSet {
nws_rootdir :: T.Text,
nws_denominator :: Integer,
nws_notemap :: [(Integer, T.Text, KeyType)]
} |
KeyWavSet {
kws_rootdir :: T.Text,
kws_wavs :: [(T.Text, KeyType)]
}
deriving (Show, Read)
data SoundMap = SoundMap {
sm_soundsets :: [(T.Text, SoundSet)],
sm_keymaps :: [[(KeyRange, T.Text)]]
}
deriving (Show, Read)
The data structure is read in like so:
sml_str <- readFile (args !! 2)
let smap = read sml_str :: SoundMap in
<moar code>
And for sanity's sake, its written out with ppShow:
writeFile (args !! 3) $ ppShow $ SoundMap {
sm_soundsets = [(wavsetname, ws)],
sm_keymaps = [[(All, wavsetname)]] }
The only caveat here is that the Read parser is sensitive to syntax errors, and is not helpful in finding them.

How to store arbitrary values in a recursive structure or how to build a extensible software architecture?

I'm working on a basic UI toolkit and am trying to figure out the overall architecture.
I am considering to use WAI's structure for extensibility. A reduced example of the core structure for my UI:
run :: Application -> IO ()
type Application = Event -> UI -> (Picture, UI)
type Middleware = Application -> Application
In WAI, arbitrary values for Middleware are saved in the vault. I think that this is a bad hack to save arbitary values, because it isn't transparent, but I can't think of a sufficient simple structure to replace this vault to give every Middleware a place to save arbitrary values.
I considered to recursively store tuples in tuples:
run :: (Application, x) -> IO ()
type Application = Event -> UI -> (Picture, UI)
type Middleware y x = (Application, x) -> (Application, (y,x))
Or to only use lazy lists to provide a level on which is no need to separate values (which provides more freedom, but also has more problems):
run :: Application -> IO ()
type Application = [Event -> UI -> (Picture, UI)]
type Middleware = Application -> Application
Actually, I would use a modified lazy list solution. Which other solutions might work?
Note that:
I prefer not to use lens at all.
I know UI -> (Picture, UI) could be defined as State UI Picture .
I'm not aware of a solution regarding monads, transformers or FRP. It would be great to see one.
Lenses provide a general way to reference data type fields so that you can extend or refactor your data set without breaking backwards compatibility. I'll use the lens-family and lens-family-th libraries to illustrate this, since they are lighter dependencies than lens.
Let's begin with a simple record with two fields:
{-# LANGUAGE Template Haskell #-}
import Lens.Family2
import Lens.Family2.TH
data Example = Example
{ _int :: Int
, _str :: String
}
makeLenses ''Example
-- This creates these lenses:
int :: Lens' Example Int
str :: Lens' Example String
Now you can write Stateful code that references fields of your data structure. You can use Lens.Family2.State.Strict for this purpose:
import Lens.Family2.State.Strict
-- Everything here also works for `StateT Example IO`
example :: State Example Bool
example = do
s <- use str -- Read the `String`
str .= s ++ "!" -- Set the `String`
int += 2 -- Modify the `Int`
zoom int $ do -- This sub-`do` block has type: `State Int Int`
m <- get
return (m + 1)
The key thing to note is that I can update my data type, and the above code will still compile. Add a new field to Example and everything will still work:
data Example = Example
{ _int :: Int
, _str :: String
, _char :: Char
}
makeLenses ''Example
int :: Lens' Example Int
str :: Lens' Example String
char :: Lens' Example Char
However, we can actually go a step further and completely refactor our Example type like this:
data Example = Example
{ _example2 :: Example
, _char :: Char
}
data Example2 = Example2
{ _int2 :: Int
, _str2 :: String
}
makeLenses ''Example
char :: Lens' Example Char
example2 :: Lens' Example Example2
makeLenses ''Example2
int2 :: Lens' Example2 Int
str2 :: Lens' Example2 String
Do we have to break our old code? No! All we have to do is add the following two lenses to support backwards compatibility:
int :: Lens' Example Int
int = example2 . int2
str :: Lens' Example Char
str = example2 . str2
Now all the old code still works without any changes, despite the intrusive refactoring of our Example type.
In fact, this works for more than just records. You can do the exact same thing for sum types, too (a.k.a. algebraic data types or enums). For example, suppose we have this type:
data Example3 = A String | B Int
makeTraversals ''Example3
-- This creates these `Traversals'`:
_A :: Traversal' Example3 String
_B :: Traversal' Example3 Int
Many of the things that we did with sum types can similarly be re-expressed in terms of Traversal's. There's a notable exception of pattern matching: it's actually possible to implement pattern matching with totality checking with Traversals, but it's currently verbose.
However, the same point holds: if you express all your sum type operations in terms of Traversal's, then you can greatly refactor your sum type and just update the appropriate Traversal's to preserve backwards compatibility.
Finally: note that the true analog of sum type constructors are Prisms (which let you build values using the constructors in addition to pattern matching). Those are not supported by the lens-family family of libraries, but they are provided by lens and you can implement them yourself using just a profunctors dependency if you want.
Also, if you're wondering what the lens analog of a newtype is, it's an Iso', and that also minimally requires a profunctors dependency.
Also, everything I've said works for reference multiple fields of recursive types (using Folds). Literally anything you can imagine wanting to reference in a data type in a backwards-compatible way is encompassed by the lens library.

Inserting a value into a Set using stateful lenses

In yet another attempt to teach myself ekmett's lens library, I'm modifying a simple text-based hangman game to use lenses instead of record updates. The code itself works, but I've come across a place where I feel like I'm using the lens library incorrectly. This code works correctly, but it just doesn't look as elegant to me as all the lens tutorials I've seen.
First, my types:
data GameState = GameState
{ _guess :: Set Char
, _secret :: String
, _wrongGuesses :: Int
} deriving (Eq, Show)
makeLenses ''GameState
type Game a = StateT GameState IO a
The function I'm bothered by is where I process the guess obtained from the user:
nextGuess :: Game ()
nextGuess = do
gs <- get -- GameState
g <- getUserGuess :: Game Char
-- If the user guessed a letter that wasn't in the secret word
when (g `notElem` gs^.secret) $
-- increment the number of wrong guesses
wrongGuesses += 1
-- Insert that guess into the set of guesses
guess .= gs^.guess.to (insert g)
I'm mostly fine with the line
when (g `notElem` gs^.secret) $ wrongGuesses += 1
But the next line, where the guess is inserted into the current set of guesses seems like a roundabout way to do it. Having to get the current set, insert, then set it again just doesn't sound like the "lens way of doing things", especially when the line before all I have to do to increment the wrongGuesses counter is use += 1.
Is there a better way to do this?
Unless I'm much mistaken,
guess %= insert g
(%=) acts as modify and will feed the Set into insert g and then stick it back into guess.

monadically iterating over a Data.Sequence

I have a Data.Sequence which I need to iterate over. The problem is that its stateful, and the sequence may grow as a result of said iteration.
data Chart = Chart {
charts :: M.Map Int (Seq.Seq RState), --map from position to list of chart states
...
} deriving (Show)
processChartSeq :: Int -> Int -> State Chart ()
processChartSeq chtIndx stIndx = do s <- get
let seq = fromJust $ M.lookup chtIndx (charts s)
rstate = Seq.index seq stIndx
processState rstate
when (stIndx < Seq.length seq) (processChartSeq chtIndx (stIndx+1))
So I'm doing this with explicit recursion, but it seems clunky. Furthermore, it seems like a common thing to do. What common monadic control structure did I re-invent, badly?
To answer the initial question, you "reinvented" the state monad within the state monad itself! You could move the stuff you're explicitly threading into your state to avoid passing it directly. On the other hand, for simple things like this, I have no problem passing things around explicitly, and often find it cleaner.
Finally, as Daniel Wagner notes, you should be pushing and popping from the top as much as possible, for the sake of efficiency.

Resources