Haskell - Creating rectangle of 1s with height and width of user input - haskell

I am trying to create a function that will take two integer values that correspond to the width and height of a rectangle of 1s that is outputted like so:
Main> rectangle 3 4
1111
1111
1111
I am a beginner at Haskell and have no experience, so any pointers would be appreciated, and therefore only basic Haskell operations should be used. Thanks.

rectangle :: Int -> Int -> String
rectangle h w = unlines (replicate h (replicate w '1'))
Although this is a pure function, it does show the relevant part. You can just putStrLn (rectangle 3 4) to have it printed out as expected in ghci, rather than wrapped in a show.
Giving it a second thought, here's a short walkthrough.
replicate :: Int -> a -> [a]
unlines :: [String] -> String
As you can see, replicate w '1'creates a list of w times the charakter 1. Because String = [Char], the result is a String of ones, as many as w says.
Now, this String is replicated again, h times, giving a list of h times that string.
unlines now concatenates those strings, inserting a new line character between the strings.
The result is what you'd expect, only that ghci (which you appear to be using) is wrapping each expression's result in a show call. So, to do exactly what you want to achieve, a call to putStr in needed as so:
impureRectangle :: Int -> Int -> IO ()
impureRectangle x y = putStr (rectangle x y)
Note that monads (or IO, as the first monad, people use to get to know as such) are not the easiest things to get your head around. I'd suggest staying pure until you feel safe.

Related

How can I generate random numbers in Haskell without IO in a range?

I would like to generate random numbers in a range and the type signature to be Int -> Int. I've read multiple other posts but none of them suggested ways to return a type Int. I used System.IO.Unsafe in my code but it is not recommended to do so. Here's my code:
import System.IO.Unsafe
-- random number generator
rng :: Int -> Int
rng upper = unsafePerformIO $ randomRIO (0,upper-1)
Does anyone have any suggests on how to generate random Int in a range in Haskell?
Edit: It might be impossible to change IO Int -> Int so I converted my code to
-- random number generator
rng :: Int -> IO Int
rng upper = randomRIO (0,upper-1)
The reason why I need a rng is because I want to get random numbers within the range length of the list to get an index for an element of a list.
list !! rng (length list) but I'm getting the error Couldn't match expected type ‘Int’ with actual type ‘IO Int’ which is expected.
It's not a duplicate because 1. I want values in a range, 2. my rng does not return the same values. I'm new to Haskell and I don't know how to manipulate Monads. Any help is appreciated.
I the spirit of https://xkcd.com/221/, here's a “solution” without any IO:
rng :: Int -> Int
rng upper
| upper<=4 = upper
| otherwise = 4
So that gives you an “RFC 1149.5 compliant random number”. It's always four, unless that is outside the range.
What's the problem with this? Well, clearly it gives always the same number – and so it must be, because all Haskell functions must be functions, i.e. referentially transparent. OTOH, a random number generator is supposed to give different number each time you call it... it is thus not a function, and most other programming languages merely pretend it is a function with side-effect – because they have no proper means to express what side-effects are. Well, Haskell does have a proper means of expressing that, and it is the IO monad: you can have computations that depend on a side effect, but clearly these computations if you run them will then have that side-effect themselves.In that light, the signature Int -> IO Int does make sense for the function. (This is a function, but the result is an IO action and only executing that action gives you an Int.)
What's ugly about that is that IO Int could literally do anything in IO – it could, for instance, launch some missiles and give you back the number of casualities. More realistically, it could easily modify some file in you home directory. Whereas what you want is actually just a teeny tiny harmless side-effect, just enough to produce a new random number the next time. Usually, random number generators are anyways not really random but PRNGs, which keep a constant-size state variable that is updated in a random-looking way each time you pull a value. The next time, this state will be different and thus you get a different value, as desired. This state variable could be held in an IO-mutable location
import Data.IORef
type RandStV = Int
type RandSt = IORef RandStV
rng' :: RandSt -> Int -> IO Int
rng' rSt upper = do
x <- readIORef rSt
let x' = ((x * 1103515245) + 12345) `mod` 0x7fffffff -- https://sourceware.org/git/?p=glibc.git;a=blob;f=stdlib/random_r.c;hb=glibc-2.26#l362
writeIORef rSt x'
return $ x `mod` upper
...or, you could just explicitly pass the updated state along with the result
rng'' :: Int -> RandStV -> (RandStV, Int)
rng'' upper x =
let x' = ((x * 1103515245) + 12345) `mod` 0x7fffffff
in (x', x `mod` upper)
...or it could be passed around in a dedicated state monad, which is just another way of writing the passing-on of an updated variable:
type RandStM = State RandStV
rng''' :: Int -> RandStM Int
rng''' upper = do
x <- get
let x' = ((x * 1103515245) + 12345) `mod` 0x7fffffff
put x'
return $ x `mod` upper
See the random-fu package for useful helpers on such a random monad.
One mathematical way to interpret rng''' is to say it is a function that takes an upper bound as the argument and gives you back a distribution of numbers. The distribution is always the same, but it “contains” many numbers together with the probability of them occuring. Actually generating an integer means you're sampling from the distribution.
Haskell was not built to generate random numbers without using IO.
Your example, list !! rng (length list), doesn't work because rng returns IO Int and !! expects a Int.
Here is a function that uses your rng function to get a random element from a list:
-- Will crash on empty list
randomElementFromList :: [a] -> IO a
randomElementFromList list = do
r <- rng (length list)
return $ list !! r

Do notation for monad in function returning a different type

Is there a way to write do notation for a monad in a function which the return type isn't of said monad?
I have a main function doing most of the logic of the code, supplemented by another function which does some calculations for it in the middle. The supplementary function might fail, which is why it is returning a Maybe value. I'm looking to use the do notation for the returned values in the main function. Giving a generic example:
-- does some computation to two Ints which might fail
compute :: Int -> Int -> Maybe Int
-- actual logic
main :: Int -> Int -> Int
main x y = do
first <- compute x y
second <- compute (x+2) (y+2)
third <- compute (x+4) (y+4)
-- does some Int calculation to first, second and third
What I intend is for first, second, and third to have the actual Int values, taken out of the Maybe context, but doing the way above makes Haskell complain about not being able to match types of Maybe Int with Int.
Is there a way to do this? Or am I heading towards the wrong direction?
Pardon me if some terminology is wrongly used, I'm new to Haskell and still trying to wrap my head around everything.
EDIT
main has to return an Int, without being wrapped in Maybe, as there is another part of the code using the result of mainas Int. The results of a single compute might fail, but they should collectively pass (i.e. at least one would pass) in main, and what I'm looking for is a way to use do notation to take them out of Maybe, do some simple Int calculations to them (e.g. possibly treating any Nothing returned as 0), and return the final value as just Int.
Well the signature is in essence wrong. The result should be a Maybe Int:
main :: Int -> Int -> Maybe Int
main x y = do
first <- compute x y
second <- compute (x+2) (y+2)
third <- compute (x+4) (y+4)
return (first + second + third)
For example here we return (first + second + third), and the return will wrap these in a Just data constructor.
This is because your do block, implicitly uses the >>= of the Monad Maybe, which is defined as:
instance Monad Maybe where
Nothing >>=_ = Nothing
(Just x) >>= f = f x
return = Just
So that means that it will indeed "unpack" values out of a Just data constructor, but in case a Nothing comes out of it, then this means that the result of the entire do block will be Nothing.
This is more or less the convenience the Monad Maybe offers: you can make computations as a chain of succesful actions, and in case one of these fails, the result will be Nothing, otherwise it will be Just result.
You can thus not at the end return an Int instead of a Maybe Int, since it is definitely possible - from the perspective of the types - that one or more computations can return a Nothing.
You can however "post" process the result of the do block, if you for example add a "default" value that will be used in case one of the computations is Nothing, like:
import Data.Maybe(fromMaybe)
main :: Int -> Int -> Int
main x y = fromMaybe 0 $ do
first <- compute x y
second <- compute (x+2) (y+2)
third <- compute (x+4) (y+4)
return (first + second + third)
Here in case the do-block thus returns a Nothing, we replace it with 0 (you can of course add another value in the fromMaybe :: a -> Maybe a -> a as a value in case the computation "fails").
If you want to return the first element in a list of Maybes that is Just, then you can use asum :: (Foldable t, Alternative f) => t (f a) -> f a, so then you can write your main like:
-- first non-failing computation
import Data.Foldable(asum)
import Data.Maybe(fromMaybe)
main :: Int -> Int -> Int
main x y = fromMaybe 0 $ asum [
compute x y
compute (x+2) (y+2)
compute (x+4) (y+4)
]
Note that the asum can still contain only Nothings, so you still need to do some post-processing.
Willem's answer is basically perfect, but just to really drive the point home, let's think about what would happen if you could write something that allows you to return an int.
So you have the main function with type Int -> Int -> Int, let's assume an implementation of your compute function as follows:
compute :: Int -> Int -> Maybe Int
compute a 0 = Nothing
compute a b = Just (a `div` b)
Now this is basically a safe version of the integer division function div :: Int -> Int -> Int that returns a Nothing if the divisor is 0.
If you could write a main function as you like that returns an Int, you'd be able to write the following:
unsafe :: Int
unsafe = main 10 (-2)
This would make the second <- compute ... fail and return a Nothing but now you have to interpret your Nothing as a number which is not good. It defeats the whole purpose of using Maybe monad which captures failure safely. You can, of course, give a default value to Nothing as Willem described, but that's not always appropriate.
More generally, when you're inside a do block you should just think inside "the box" that is the monad and don't try to escape. In some cases like Maybe you might be able to do unMaybe with something like fromMaybe or maybe functions, but not in general.
I have two interpretations of your question, so to answer both of them:
Sum the Maybe Int values that are Just n to get an Int
To sum Maybe Ints while throwing out Nothing values, you can use sum with Data.Maybe.catMaybes :: [Maybe a] -> [a] to throw out Nothing values from a list:
sum . catMaybes $ [compute x y, compute (x+2) (y+2), compute (x+4) (y+4)]
Get the first Maybe Int value that's Just n as an Int
To get the first non-Nothing value, you can use catMaybes combined with listToMaybe :: [a] -> Maybe a to get Just the first value if there is one or Nothing if there isn't and fromMaybe :: a -> Maybe a -> a to convert Nothing to a default value:
fromMaybe 0 . listToMaybe . catMaybes $ [compute x y, compute (x+2) (y+2), compute (x+4) (y+4)]
If you're guaranteed to have at least one succeed, use head instead:
head . catMaybes $ [compute x y, compute (x+2) (y+2), compute (x+4) (y+4)]

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 handle side effect with Applicative?

I see everywhere that Applicative can handle side effects, but all the simple examples I've seen are just combining stuff together like:
> (,,) <$> [1,2] <*> ["a", "b", "c"] <*> ["foo", "bar"]
[(1,"a","foo"),(1,"a","bar"),(1,"b","foo"),(1,"b","bar"),
(1,"c","foo"),(1,"c","bar"),(2,"a","foo"),(2,"a","bar"),
(2,"b","foo"),(2,"b","bar"),(2,"c","foo"),(2,"c","bar")]
Which is cool but I can't see how that links to side effects. My understanding is that Applicative is a weak monad and so you can handle side effects (as you would do with a State monad) but you can't reuse the result of the previous side effect.
Does that mean that >> could be written for an Applicative and things like
do
print' "hello"
print' "world"
would make sense (with print' :: a -> Applicative something) (with the appropriate do-applicative extension).
In other world, is the difference between Monad and Applicative is that Monad allows x <- ... but Applicative doesn't.
Then, is the Writer monad, just an applicative?
Output
The applicative equivalent for >> is *>, so you can do
ghci> :m Control.Applicative
ghci> print 5 *> print 7
5
7
Input - a better case for Applicative
import Control.Applicative
data Company = Company {name :: String, size :: Int}
deriving Show
getCompany :: IO Company
getCompany = Company <$> getLine <*> readLn
Which works nicely for input:
ghci> getCompany >>= print
BigginsLtd
3
Company {name = "BigginsLtd", size = 3}
Notice that since we're using Applicative for IO, we're in the IO monad anyway, so can use >>= if we like. The benefit Applicative gives you is the nice syntax.
My favourite is with parsing, so I can do
data Statement = Expr Expression | If Condition Statement Statement
parseStatement = Expr <$> parseExpression <|>
If <$> (string "if" *> parseCondition)
<*> (string "then" *> parseStatement)
<*> (string "else" *> parseStatement)
The difference between Applicative and Monad
The difference between Applicative and Monad is that Monad has >>=, which lets you choose what side effect to use based on the value you have.
Using Monad:
don't_reformat_hard_drive :: Bool -> IO ()
don't_reformat_hard_drive yes = if yes then putStr "OK I didn't"
else putStr "oops!" >> System.IO.reformat "C:/"
maybeReformat :: IO ()
maybeReformat = WinXP.Dialogs.ask "Don't reformat hard drive?"
>>= don't_reformat_hard_drive
(There's no System.IO.reformat or WinXP.Dialogs.ask. This is just an example I found funny.)
Using Applicative:
response :: Bool -> () -> String
response yes () = if yes then "OK I didn't" else "oops!"
probablyReformat = response <$> WinXP.Dialogs.ask "Don't reformat hard drive?"
<*> System.IO.reformat "C:\"
Sadly, using Applicative I can't inspect the Boolean value to determine whether to reformat or not – the side effect order is determined at compile time, in an Applicative, and the hard drive will always be reformatted with this piece of code. I need the Monad's bind (>>=) to be able to stop the reformat.
.........your hard drive C: has been successfully reformatted.
"OK I didn't"
Applicative and Monad both provide ways of "combining" multiple side-effectful1 values into a single side-effectful value.
The Applicative interface for combining just lets you combine effectful values such that the resulting effectful value combines all their effects according to some "fixed" recipe.
The Monad interface for combining lets you combine effectful values in such a way that the effects of the combined value depends on what the original effectful values do when they're actually resolved.
For example, the State Integer monad/applicative is of values that depend upon (and affect) some Integer state. State Integer t values only have a concrete value in the presence of that state.
A function that takes two State Integer Char values (call them a and b) and gives us back a State Integer Char value and only uses the Applicative interface of State Integer must produce a value whose "statefulness" is always the same, regardless of what the Integer state value is and regardless of what Char values the inputs yield. For example, it could thread the state through a and then b, combining their Char values somehow. Or it could threat the state through b and then a. Or it could pick only a or only b. Or it could ignore both entirely, not taking either of their effects on the current Integer state, and just pure some char value. Or it could run either or both of them any fixed number of times in any fixed order, and it could incorporate any other State Integer t values it knows about. But whatever it does, it always does that, regardless of the current Integer state, or any values produced by any of the State Integer t values it manages to get its hands on.
A function that took the same inputs but was able to use the monad interface for State Integer can do much more than that. It can run a or b depending on whether the current Integer state is positive or negative. It can run a, then if the resulting Char is an ascii digit character it can turn the digit into a number and run b that many times. And so on.
So yes, a computation like:
do
print' "hello"
print' "world"
Is one that could be implemented using only the Applicative interface to whatever print' returns. You are close to correct that the difference between Monad and Applicative if both had a do-notation would be that monadic do would allow x <- ..., while applicative do would not. It's a bit more subtle than that though; this would work with Applicative too:
do x <- ...
y <- ...
pure $ f x y
What Applicative can't do is inspect x and y to decide what f to call on them (or do anything with the result of f x y other than just pure it.
You are not quite correct that there's no difference between Writer w as a monad and as an applicative, however. It's true that the monadic interface of Writer w doesn't allow the value yielded to depend on the effects (the "log"), so it must always be possible to rewrite any Writer w defined using monadic features to one that only uses applicative features and always yields the same value2. But the monadic interface allows the effects to depend on the values, which the applicative interface doesn't, so you can't always faithfully reproduce the effects of a Writer w using only the applicative interface.
See this (somewhat silly) example program:
import Control.Applicative
import Control.Monad.Writer
divM :: Writer [String] Int -> Writer [String] Int -> Writer [String] Int
divM numer denom
= do d <- denom
if d == 0
then do tell ["divide by zero"]
return 0
else do n <- numer
return $ n `div` d
divA :: Writer [String] Int -> Writer [String] Int -> Writer [String] Int
divA numer denom = divIfNotZero <$> numer <*> denom
where
divIfNotZero n d = if d == 0 then 0 else n `div` d
noisy :: Show a => a -> Writer [String] a
noisy x = tell [(show x)] >> return x
Then with that loaded in GHCi:
*Main> runWriter $ noisy 6 `divM` noisy 3
(2,["3","6"])
*Main> runWriter $ noisy 6 `divM` noisy 0
(0,["0","divide by zero"])
*Main> runWriter $ undefined `divM` noisy 0
(0,["0","divide by zero"])
*Main> runWriter $ noisy 6 `divA` noisy 3
(2,["6","3"])
*Main> runWriter $ noisy 6 `divA` noisy 0
(0,["6","0"])
*Main> runWriter $ undefined `divA` noisy 0
(0,*** Exception: Prelude.undefined
*Main> runWriter $ (tell ["undefined"] *> pure undefined) `divA` noisy 0
(0,["undefined","0"])
Note how with divM, whether numer's effects are included in numer `divM` denom depends on the value of denom (as does whether the effect of tell ["divide by zero"]). With the best the applicative interface can do, the effects of numer are always included in numerdivAdenom, even when lazy evaluation should mean that the value yielded by numer is never inspected. And it's not possible to helpfully add "divide by 0" to the log when the denominator is zero.
1 I don't like to think of "combining effectful values" as the definition of that monads and applicatives do, but it's an example of what you can do with them.
2 When bottoms aren't involved, anyway; you should be able to see from my example why bottom can mess up the equivalence.
In your example, the Applicative instance for lists is being used. The "effect" here is nondeterminism: returning more than one possible value.
The Applicative instance for lists calculates the possible combinations of elements from the individual list arguments.
However, what it can't do is make one of the lists depend on values contained in a previous list. You need the Monad instance for that.
For example, consider the code:
foo :: [Int]
foo = do
r <- [2,7]
if (even r)
then [2,5,6]
else [9,234,343]
Here we are generating lists whose values depend on a list that appeared earlier in the computation (the [2,7] one). You can't do that with Applicative.
An analogy
I hope the following analogy is not too obtuse, but Applicatives are like railroads.
In an Applicative, effects build the railroad upon which the locomotive of function application will travel. All the effects take place while building the railroad, not when the locomotive moves. The locomotive cannot change its course in any way.
A Monad is like having a locomotive in a railroad which is still under construction. Passengers can actually yell to the construction crew a few meters ahead to tell them things like "I like the scenery on this side, please lay the tracks a bit more towards the right" or "you can stop laying tracks, I get out right here". Of course, for this strange railway, the company can't provide a timetable or a fixed list of stops that can be checked before embarking on the train.
That's why Applicatives can be regarded as a form of "generalized function application", but Monads can't.

Storing values in a data structure Haskell

I'm trying to store randomly generated dice values in some data structure, but don't know how exactly to do it in Haskell. I have so far, only been able to generate random ints, but I want to be able to compare them to the corresponding color values and store the colors instead (can't really conceive what the function would look like). Here is the code I have --
module Main where
import System.IO
import System.Random
import Data.List
diceColor = [("Black",1),("Green",2),("Purple",3),("Red",4),("White",5),("Yellow",6)]
diceRoll = []
rand :: Int -> [Int] -> IO ()
rand n rlst = do
num <- randomRIO (1::Int, 6)
if n == 0
then printList rlst -- here is where I need to do something to store the values
else rand (n-1) (num:rlst)
printList x = putStrLn (show (sort x))
--matchColor x = doSomething()
main :: IO ()
main = do
--hSetBuffering stdin LineBuffering
putStrLn "roll, keep, score?"
cmd <- getLine
doYahtzee cmd
--rand (read cmd) []
doYahtzee :: String -> IO ()
doYahtzee cmd = do
if cmd == "roll"
then do rand 5 []
else putStrLn "Whatever"
After this, I want to be able to give the user the ability to keep identical dices (as in accumulate points for it) and give them a choice to re-roll the left over dices - I'm thinking this can done by traversing the data structure (with the dice values) and counting the repeating dices as points and storing them in yet another data structure. If the user chooses to re-roll he must be able to call random again and replace values in the original data structure.
I'm coming from an OOP background and Haskell is new territory for me. Help is much appreciated.
So, several questions, lets take them one by one :
First : How to generate something else than integers with the functions from System.Random (which is a slow generator, but for your application, performance isn't vital).
There is several approaches, with your list, you would have to write a function intToColor :
intToColor :: Int -> String
intToColor n = head . filter (\p -> snd p == n) $ [("Black",1),("Green",2),("Purple",3),("Red",4),("White",5),("Yellow",6)]
Not really nice. Though you could do better if you wrote the pair in the (key, value) order instead since there's a little bit of support for "association list" in Data.List with the lookup function :
intToColor n = fromJust . lookup n $ [(1,"Black"),(2,"Green"),(3,"Purple"),(4,"Red"),(5,"White"),(6,"Yellow")]
Or of course you could just forget this business of Int key from 1 to 6 in a list since lists are already indexed by Int :
intToColor n = ["Black","Green","Purple","Red","White","Yellow"] !! n
(note that this function is a bit different since intToColor 0 is "Black" now rather than intToColor 1, but this is not really important given your objective, if it really shock you, you can write "!! (n-1)" instead)
But since your colors are not really Strings and more like symbols, you should probably create a Color type :
data Color = Black | Green | Purple | Red | White | Yellow deriving (Eq, Ord, Show, Read, Enum)
So now Black is a value of type Color, you can use it anywhere in your program (and GHC will protest if you write Blak) and thanks to the magic of automatic derivation, you can compare Color values, or show them, or use toEnum to convert an Int into a Color !
So now you can write :
randColorIO :: IO Color
randColorIO = do
n <- randomRIO (0,5)
return (toEnum n)
Second, you want to store dice values (colors) in a data structure and give the option to keep identical throws. So first you should stock the results of several throws, given the maximum number of simultaneous throws (5) and the complexity of your data, a simple list is plenty and given the number of functions to handle lists in Haskell, it is the good choice.
So you want to throws several dices :
nThrows :: Int -> IO [Color]
nThrows 0 = return []
nThrows n = do
c <- randColorIO
rest <- nThrows (n-1)
return (c : rest)
That's a good first approach, that's what you do, more or less, except you use if instead of pattern matching and you have an explicit accumulator argument (were you going for a tail recursion ?), not really better except for strict accumulator (Int rather than lists).
Of course, Haskell promotes higher-order functions rather than direct recursion, so let's see the combinators, searching "Int -> IO a -> IO [a]" with Hoogle gives you :
replicateM :: Monad m => Int -> m a -> m [a]
Which does exactly what you want :
nThrows n = replicateM n randColorIO
(I'm not sure I would even write this as a function since I find the explicit expression clearer and almost as short)
Once you have the results of the throws, you should check which are identical, I propose you look at sort, group, map and length to achieve this objective (transforming your list of results in a list of list of identical results, not the most efficient of data structure but at this scale, the most appropriate choice). Then keeping the colors you got several time is just a matter of using filter.
Then you should write some more functions to handle interaction and scoring :
type Score = Int
yahtzee :: IO Score
yahtzeeStep :: Int -> [[Color]] -> IO [[Color]] -- recursive
scoring :: [[Color]] -> Score
So I recommend to keep and transmit a [[Color]] to keeps track of what was put aside. This should be enough for your needs.
You are basically asking two different questions here. The first question can be answered with a function like getColor n = fst . head $ filter (\x -> snd x == n) diceColor.
Your second question, however, is much more interesting. You can't replace elements. You need a function that can call itself recursively, and this function will be driving your game. It needs to accept as parameters the current score and the list of kept dice. On entry the score will be zero and the kept dice list will be empty. It will then roll as many dice as needed to fill the list (I'm not familiar with the rules of Yahtzee), output it to the user, and ask for choice. If the user chooses to end the game, the function returns the score. If he chooses to keep some dice, the function calls itself with the current score and the list of kept dice. So, to sum it up, playGame :: Score -> [Dice] -> IO Score.
Disclaimer: I am, too, very much a beginner in Haskell.
at first thought:
rand :: Int -> IO [Int]
rand n = mapM id (take n (repeat (randomRIO (1::Int, 6))))
although the haskellers could remove the parens

Resources