Skip to content

Instantly share code, notes, and snippets.

@MathiasSven
Created January 25, 2024 20:29
Show Gist options
  • Save MathiasSven/86a2806bac3a8b75b1db7a7e9ebfcea5 to your computer and use it in GitHub Desktop.
Save MathiasSven/86a2806bac3a8b75b1db7a7e9ebfcea5 to your computer and use it in GitHub Desktop.
PrimVar vs IORef vs Parameters

PrimVar:

1:

real    0m39.444s
user    0m39.348s
sys     0m0.058s

2:

real    0m39.715s
user    0m39.621s
sys     0m0.056s

3:

real    0m40.055s
user    0m39.964s
sys     0m0.039s

Code

runBrainfuck :: Brainfuck -> IO ()
runBrainfuck bf = do
  dataPointer <- newPrimVar (0 :: Word16)
  arr <- MV.replicate @_ @Word8 (fromIntegral (maxBound @Word16) + 1) 0

  let readRef = fromIntegral <$> readPrimVar dataPointer
      modifyRef = modifyPrimVar dataPointer

  bf & fix \evalLoop bf' ->
    forM_ bf' \case
      Op OpInc    -> readRef >>= MV.modify arr (+ 1)
      Op OpDec    -> readRef >>= MV.modify arr (- 1)
      Op OpLeft   -> modifyRef (- 1)
      Op OpRight  -> modifyRef (+ 1)
      Op OpOutput -> readRef >>= MV.read arr >>= putChar . w2c
      Op OpInput  -> join $ liftM2 (MV.write arr) readRef (c2w <$> getChar)
      Loop bf''   -> fix \recurse -> do
        state <- readRef >>= MV.read arr
        unless (state == 0) (evalLoop bf'' >> recurse)

  putChar '\n'

IORef

1:

real    1m27.346s
user    1m27.183s
sys     0m0.096s

2:

real    1m27.948s
user    1m27.702s
sys     0m0.117s

3: TL, didn't wait

Code

runBrainfuck :: Brainfuck -> IO ()
runBrainfuck bf = do
  dataPointer <- newIORef (0 :: Word16)
  arr <- MV.replicate @_ @Word8 (fromIntegral (maxBound @Word16) + 1) 0

  let readRef = fromIntegral <$> readIORef dataPointer
      modifyRef = modifyIORef dataPointer

  bf & fix \evalLoop bf' ->
    forM_ bf' \case
      Op OpInc    -> readRef >>= MV.modify arr (+ 1)
      Op OpDec    -> readRef >>= MV.modify arr (- 1)
      Op OpLeft   -> modifyRef (- 1)
      Op OpRight  -> modifyRef (+ 1)
      Op OpOutput -> readRef >>= MV.read arr >>= putChar . w2c
      Op OpInput  -> join $ liftM2 (MV.write arr) readRef (c2w <$> getChar)
      Loop bf''   -> fix \recurse -> do
        state <- readRef >>= MV.read arr
        unless (state == 0) (evalLoop bf'' >> recurse)

  putChar '\n'

Parameters

1:

real    0m50.884s
user    0m50.846s
sys     0m0.040s

2:

real    0m52.145s
user    0m52.083s
sys     0m0.048s

3:

real    0m51.155s
user    0m51.108s
sys     0m0.046s

Code

runBrainfuck :: Brainfuck -> IO ()
runBrainfuck bf = do
  arr <- MV.replicate @_ @Word8 (fromIntegral (maxBound @Word16) + 1) 0

  let dataPointer = (0 :: Word16)
      w2i = fromIntegral

      evalLoop :: Word16 -> Brainfuck -> IO Word16
      evalLoop !dp = \case
        []             -> return dp
        Op OpInc:xs    -> MV.modify arr (+ 1) (w2i dp) >> evalLoop dp xs
        Op OpDec:xs    -> MV.modify arr (- 1) (w2i dp) >> evalLoop dp xs
        Op OpLeft:xs   -> evalLoop (dp - 1) xs
        Op OpRight:xs  -> evalLoop (dp + 1) xs
        Op OpOutput:xs -> MV.read arr (w2i dp) >>= putChar . w2c >> evalLoop dp xs
        Op OpInput:xs  -> (MV.write arr (w2i dp) . c2w =<< getChar) >> evalLoop dp xs
        Loop bf'':xs   -> let loop !dp' = do
                                state <- MV.read arr (w2i dp')
                                if state /= 0 then evalLoop dp' bf'' >>= loop else evalLoop dp' xs
                          in loop dp

  evalLoop dataPointer bf

  putChar '\n'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment