Home How do I update the values of these Int refs (Haskell)?
Reply: 1

How do I update the values of these Int refs (Haskell)?

user8930358
1#
user8930358 Published in 2017-11-13 14:58:30Z

I have some variables like so:

let y0 = read (input!!0) :: Int
let h = read (input!!1) :: Int
y <- newIORef y0
minY <- newIORef 0 
maxY <- newIORef (h - 1) 

And later I have

y_old <- readIORef y

if (some_string!!0 == 'U') then   
    maxY = (y_old - 1)       --I don't think this is working
else if (some_string!!0 == 'D') then
    minY = (y_old + 1)       --I don't think this is working

I am basically reading the references into some local ints and then trying to update the references based on criteria.

I also tried modifyIORef maxY (y_old - 1) but this doesn't work either. The compiler is only telling me "parse error" or "syntax error" which is not helpful.

My full code:

import System.IO
import Control.Monad
import Data.IORef
import Text.Printf

main :: IO ()
main = do
    hSetBuffering stdout NoBuffering -- DO NOT REMOVE

    -- Auto-generated code below aims at helping you parse
    -- the standard input according to the problem statement.

    input_line <- getLine
    let input = words input_line
    let w = read (input!!0) :: Int -- width of the building.
    let h = read (input!!1) :: Int -- height of the building.
    input_line <- getLine
    let n = read input_line :: Int -- maximum number of turns before game over.
    input_line <- getLine
    let input = words input_line
    let x0 = read (input!!0) :: Int
    let y0 = read (input!!1) :: Int
    x <- newIORef x0
    y <- newIORef y0
    minX <- newIORef 0 
    maxX <- newIORef (w - 1) 
    minY <- newIORef 0 
    maxY <- newIORef (h - 1) 
    loop x0 y0 w h x y minX maxX minY maxY

loop :: Int -> Int -> Int -> Int -> IORef Int -> IORef Int -> IORef Int -> IORef Int-> IORef Int -> IORef Int -> IO ()
loop x0 y0 w h x y minX maxX minY maxY = do
    input_line <- getLine
    let bombdir = input_line :: String -- the direction of the bombs from batman's current location (U, UR, R, DR, D, DL, L or UL)

    x_old <- readIORef x 
    y_old <- readIORef y

    if (bombdir!!0 == 'U') then
        writeIORef maxY (y_old - 1)
    if (bombdir!!0 == 'D') then
        writeIORef minY (y_old + 1)

    if (bombdir!!(bombdir.length-1) == 'L') then
        writeIORef maxX (x_old - 1)
    if (bombdir!!(bombdir.length-1) == 'R') then
        writeIORef minX (x_old + 1)


    x = (minX + maxX) / 2
    y = (minY + maxY) / 2

    x_out <- readIORef x 
    y_out <- readIORef y


    printf "%d %d" x_out y_out
    loop x0 y0 w h x y minX maxX minY maxY
leftaroundabout
2#
leftaroundabout Reply to 2017-11-14 11:23:51Z

First a bit of good style:

    ...
    input_line <- getLine
    let input = words input_line
    let w = read (input!!0) :: Int -- width of the building.
    let h = read (input!!1) :: Int -- height of the building.

This works, but it's awkward. You build up a list and give it a name, only to access individual elements, parse them one-by-one and give them new names. Why not just

    input_line <- getLine
    let [w,h] = map read (words input_line) :: [Int]

In fact, you don't even need input_line, nor the signatures (provided you later use w and h, so their types are unambiguous). I.e., the following also does the trick:

    [w,h] <- map read . words <$> getLine

Likewise,

    [x₀,y₀] <- map read . words <$> getLine

The real problem with your code in loop is that you try to use if as a procedural control-flow statement. Haskell doesn't have control flow, it only has expressions. Hence Haskell's if is actually very different from the if statement in imperative languages, it's more like the ? : operator. One thing you could do is complete these conditionals to

    if (bombdir!!0 == 'U')
     then writeIORef maxY (y_old - 1)
     else pure ()

...pure () being the no-op in a pseudo-imperative (monadic) do block. But there's a standard combinator for this particular construct, when. It's actually just a library function, but behaves almost exactly like if in imperative languages. With that, you could make it

    when (bombdir!!0 == 'U') $ writeIORef maxY (y_old - 1)

But I wouldn't recommend it. You're again do awkward list-element accessing. A much nicer way of deciding what to do depending on values of list-elements is directly pattern-matching them with a case expression:

loop :: Int -> Int -> Int -> Int
 -> IORef Int -> IORef Int -> IORef Int -> IORef Int-> IORef Int -> IORef Int -> IO ()
loop x₀ y₀ w h x y minX maxX minY maxY = do

    bombdir <- getLine  -- no need to first name it `input_line`

    x_old <- readIORef x 
    y_old <- readIORef y

    case bomdir of
      ('U':_) -> writeIORef maxY (y_old - 1)
      ('D':_) -> writeIORef minY (y_old + 1)
      _       -> pure ()

    case reverse bombdir of
      ('L':_) -> writeIORef maxX (x_old - 1)
      ('R':_) -> writeIORef minX (x_old + 1)
      _       -> pure ()

Then, you attempt to do arithmetic directly on IORefs, instead of on pure values. This is generally eschewed; what you'd actually need to write is

    writeIORef x =<< do
        xmin <- readIORef minX
        xmax <- readIORef maxX
        pure $ (xmin + xmax) / 2

I think we agree that this looks horrible, but it works. A more concise way of writing it would be

    writeIORef x =<< (/2) <$> ((+) <$> readIORef minX <*> readIORef maxX)

As I already commented, you fortunately don't need those ugly IORefs at all. Just make “new versions” of your variables to pass in the recursive call:

loop :: Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int-> Int -> Int -> IO ()
loop x₀ y₀ w h x y minX maxX minY maxY = do
    bombdir <- input_line

    let (maxY',minY') = case bombdir of
          ('U':_) -> (y - 1, minY )
          ('D':_) -> (maxY , y + 1)
        (maxX',minX') = case reverse bombdir of
          ('L':_) -> (x - 1, minX )
          ('R':_) -> (maxX , x + 1)

        x' = (minX' + maxX') / 2
        y' = (minY' + maxY') / 2

    printf "%d %d" x' y'
    loop x₀ y₀ w h x' y' minX' maxX' minY' maxY'
You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.333266 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO