Stateful integer generation in Haskell - haskell

I'd like to write a Haskell function to generate integers. The function would return 1 the first time it is called, then return the next integer each subsequent time the function is called.
In Python I've used the idea of generators — an integer generator might look something like this:
def intGen():
x = 1
while True:
yield x
x += 1
integer = intGen()
# Use the generator
next(integer) # 1
next(integer) # 2
next(integer) # 3
How do I accomplish something like this in Haskell? I know I probably need the State monad, but I'm not quite sure on how to set that up; I am fairly new to monads.

Haskell is pure, function can't generate different data on same arguments.
If you really want to use it, you should use IO a or ST a data, like IORef a and STRef a.
But you could use pure methods in different way:
intGen = [1 .. 10]
intRes = map next intGen

Using IORefs, you could do something like
import Data.IORef
import Control.Monad ((=<<))
type IntGen = IORef Int
intGen :: IO IntGen
intGen = newIORef 1
next :: IntGen -> IO Int
next gen = do
val <- readIORef gen
writeIORef gen $ val + 1
return val
main :: IO ()
main = do
integer <- intGen
-- f =<< m == m >>= f
print =<< next integer
print =<< next integer
print =<< next integer
Or you can use the State monad to do this purely:
import Control.Monad.State
next :: Monad m => StateT Int m Int
next = do
val <- get
put $ val + 1
return val
app :: StateT Int IO ()
app = do
let stprint = liftIO . print
stprint =<< next
stprint =<< next
stprint =<< next
main :: IO ()
main = void $ runStateT app 1
In the second one, your initial value is the 1 supplied to runStateT, so it's more flexible in that you can start from different values.
All this being said, usually when you need lazily generated integer values, a list is the way to go. For example, I might have something like
def processFile(directory):
integer = intGen()
for fname in os.listdir(directory):
full_fname = os.path.join(directory, fname)
if os.path.isfile(full_fname):
i = next(integer)
new_fname = '{}-{}'.format(i, fname)
os.rename(full_fname, os.path.join(directory, new_fname))
but in Haskell I'd prefer to write something like
import Control.Monad
import System.Directory
import System.FilePath
processFiles :: FilePath -> IO ()
processFiles directory = do
contents <- getDirectoryContents directory
files <- filterM doesFileExist $ map (directory </>) contents
forM_ (zip [1..] files) $ \(i, fname) -> do
let newFName = show i ++ "-" ++ fname
renameFile (directory </> fname) (directory </> newFName)

Related

Pipes (Haskell lib) - piping pipes with different state monad

My goal is to have the last value produced equal to 80 (40 + 40) (see code below)...
import Pipes
import Pipes.Prelude
import Pipes.Lift
import Control.Monad.State.Strict
data Input = A Integer | B Integer | C Integer
main :: IO ()
main = runEffect $ each [A 10,B 2,C 3,A 40,A 40] >-> pipeline >-> print
pipeline :: Pipe Input Integer IO ()
pipeline = for cat $ \case
A x -> yield x >-> accumulate
B x -> yield x
C x -> yield x
accumulate :: Pipe Integer Integer IO ()
accumulate = evalStateP 0 accumulate'
accumulate' :: Pipe Integer Integer (StateT Integer IO) ()
accumulate' = go
where
go = do
x <- await
lift $ modify (+x)
r <- lift get
yield r
go
With this example Input As are not accumulated...yield x >-> accumulate on Input A does do what I'm expected, the stream is a new one each time...
Piping pipes with different state monad sequentially works well but here somehow I want to nest them in the case pattern (like a substream somehow)...
The problem is that you call evalStateP too early, discarding state you want to preserve across calls to accumulate. Try something like this:
pipeline :: Pipe Input Integer IO ()
pipeline = evalStateP 0 $ for cat $ \case
A x -> yield x >-> accumulate
B x -> yield x
C x -> yield x
accumulate :: Pipe Integer Integer (StateT Integer IO) ()
accumulate = for cat $ \x -> do
modify (+x)
r <- get
yield r
Note that Proxy has a MonadState instance, so you don't need to lift state operations manually if you use mtl.

State monad: How to `print` intermediate value in Haskell

I'm new in haskell and I have following code
module StateTest where
import Control.Monad.State.Lazy
tick :: State Int Int
tick = do n <- get
put (n+1)
return n
plusOne :: Int -> Int
plusOne = execState tick
main = print $ plusOne 1
And I want to print state value after put (n+1) and continue computation like this
tick = do n <- get
put (n+1)
print
return n
How whole code will look following to this?
If you want to run IO actions within a state computation you can change the type of tick to return a StateT Int IO Int and use liftIO. Then you can run it using execStateT:
import Control.Monad.State.Lazy
import Control.Monad.IO.Class (liftIO)
tick :: StateT Int IO Int
tick = do n <- get
put (n+1)
liftIO $ print (n+1)
return n
plusOne :: Int -> IO Int
plusOne = execStateT tick
main = plusOne 1 >> pure ()
Another option, since you would have to use IO anyway to print a value in the intermediate state, would be to use IORef. It's a container that has an updateable value.
module Main where
import Data.IORef
tick :: IORef Int -> IO (IORef Int)
tick ref = do
modifyIORef' ref (+1)
-- you can also print here since it is IO
pure ref
main :: IO ()
main = do
counter <- newIORef 0
tick counter
v2 <- readIORef counter
print v2
tick counter
v2 <- readIORef counter
print v2
You can then clean it up with ReaderT.
module Main where
import Data.IORef
import Control.Monad.Reader
readerTick :: ReaderT (IORef Int) IO ()
readerTick = do
ref <- ask
-- can also print here with liftIO $ print ...
liftIO $ modifyIORef' ref (+1)
main :: IO ()
main = do
counter <- newIORef 0
runReaderT readerTick counter
v1 <- readIORef counter
print v1
runReaderT readerTick counter
v2 <- readIORef counter
print v2

Simple Haskell program not behaving correct

I'm new to Haskell and trying to write simple program to find maximal element and it's index from intput. I receive values to compare one by one. Maximal element I'm holding in maxi variable, it's index - in maxIdx. Here's my program:
loop = do
let maxi = 0
let maxIdx = 0
let idx = 0
let idxN = 0
replicateM 5 $ do
input_line <- getLine
let element = read input_line :: Int
if maxi < element
then do
let maxi = element
let maxIdx = idx
hPutStrLn stderr "INNER CHECK"
else
hPutStrLn stderr "OUTER CHECK"
let idx = idxN + 1
let idxN = idx
print maxIdx
loop
Even though I know elements coming are starting from bigger to smaller (5, 4, 3, 2, 1) program enters INNER CHECK all the time (it should happen only for the first element!) and maxIdx is always 0.
What am I doing wrong?
Thanks in advance.
Anyway, let's have fun.
loop = do
let maxi = 0
let maxIdx = 0
let idx = 0
let idxN = 0
replicateM 5 $ do
input_line <- getLine
let element = read input_line :: Int
if maxi < element
then do
let maxi = element
let maxIdx = idx
hPutStrLn stderr "INNER CHECK"
else
hPutStrLn stderr "OUTER CHECK"
let idx = idxN + 1
let idxN = idx
print maxIdx
loop
is not a particularly Haskelly code (and as you know is not particularly correct).
Let's make if Haskellier.
What do we do here? We've an infinite loop, which is reading a line 5 times, does something to it, and then calls itself again for no particular reason.
Let's split it:
import Control.Monad
readFiveLines :: IO [Int]
readFiveLines = replicateM 5 readLn
addIndex :: [Int] -> [(Int, Int)]
addIndex xs = zip xs [0..]
findMaxIndex :: [Int] -> Int
findMaxIndex xs = snd (maximum (addIndex xs))
loop :: ()
loop = loop
main :: IO ()
main = do xs <- readFiveLines
putStrLn (show (findMaxIndex xs))
snd returns the second element from a tuple; readLn is essentially read . getLine; zip takes two lists and returns a list of pairs; maximum finds a maximum value.
I left loop intact in its original beauty.
You can be even Haskellier if you remember that something (huge expression) can be replaced with something $ huge expression ($ simply applies its left operand to its right operand), and the functions can be combined with .: f (g x) is the same as (f . g) x, or f . g $ x (see? it's working for the left side as well!). Additionally, zip x y can be rewritten as x `zip` y
import Control.Monad
readFiveLines :: IO [Int]
readFiveLines = replicateM 5 readLn
addIndex :: [Int] -> [(Int, Int)]
addIndex = (`zip` [0..])
findMaxIndex :: [Int] -> Int
findMaxIndex = snd . maximum . addIndex
main :: IO ()
main = do xs <- readFiveLines
putStrLn . show . findMaxIndex $ xs
As for debug print, there's a package called Debug.Trace and a function traceShow which prints its first argument (formatted with show, hence the name) to stderr, and returns its second argument:
findMaxIndex :: [Int] -> Int
findMaxIndex = snd . (\xs -> traceShow xs (maximum xs)) . addIndex
That allows you to tap onto any expression and see what's coming in (and what are the values around — you can show tuples, lists, etc.)
I think alf's answer is very good, but for what it's worth, here's how I would interpret your intention.
{-# LANGUAGE FlexibleContexts #-}
module Main where
import System.IO
import Control.Monad.State
data S = S { maximum :: Int
, maximumIndex :: Int
, currentIndex :: Int }
update :: Int -> Int -> S -> S
update m mi (S _ _ ci) = S m mi ci
increment :: S -> S
increment (S m mi ci) = S m mi (ci+1)
next :: (MonadIO m, MonadState S m) => m ()
next = do
S maxi maxIdx currIdx <- get
input <- liftIO $ getLine
let element = read input :: Int
if maxi < element
then do
modify (update element currIdx)
liftIO $ hPutStrLn stderr "INNER CHECK"
else
liftIO $ hPutStrLn stderr "OUTER CHECK"
modify increment
run :: Int -> IO S
run n = execStateT (replicateM_ n next) (S 0 0 0)
main :: IO ()
main = do
S maxi maxIdx _ <- run 5
putStrLn $ "maxi: " ++ (show maxi) ++ " | maxIdx: " ++ (show maxIdx)
This uses a monad transformer to combine a stateful computation with IO. The get function retrieves the current state, and the modify function lets you change the state.

Haskell: how to read values from stdin line-by-line and add them to a map?

I want to read strings from stdin and store them into a map, where key is the input string and value is the number of previous occurrences of this string. In Java I would have done something like this:
for (int i = 0; i < numberOfLines; i++) {
input = scanner.nextLine();
if (!map.containsKey(input)) {
map.put(input, 0);
System.out.println(input);
} else {
int num = map.get(input) + 1;
map.remove(input);
map.put(input, num);
System.out.println(input.concat(String.valueOf(num));
}
}
I've tried doing the same in Haskell by using forM_ but had no luck.
import Control.Monad
import qualified Data.Map as Map
import Data.Maybe
main = do
input <- getLine
let n = read input :: Int
let dataset = Map.empty
forM_ [1..n] (\i -> do
input <- getLine
let a = Map.lookup input dataset
let dataset' =
if isNothing a then
Map.insert input 0 dataset
else
Map.insert input num (Map.delete input dataset)
where num = ((read (fromJust a) :: Int) + 1)
let dataset = dataset'
let output = if isNothing a then
input
else
input ++ fromJust a
putStrLn output)
The contents of dataset in the above code does not change at all.
The Map defined in Data.Map is an immutable data type. Calling Map.insert returns a modified Map, it does not change the one you already have. What you want to do is iteratively apply updates in a loop. Something more like
import qualified Data.Map as M
import Data.Map (Map)
-- Adds one to an existing value, or sets it to 0 if it isn't present
updateMap :: Map String Int -> String -> Map String Int
updateMap dataset str = M.insertWith updater str 0 dataset
where
updater _ 0 = 1
updater _ old = old + 1
-- Loops n times, returning the final data set when n == 0
loop :: Int -> Map String Int -> IO (Map String Int)
loop 0 dataset = return dataset
loop n dataset = do
str <- getLine
let newSet = updateMap dataset str
loop (n - 1) newSet -- recursively pass in the new map
main :: IO ()
main = do
n <- fmap read getLine :: IO Int -- Combine operations into one
dataset <- loop n M.empty -- Start with an empty map
print dataset
Notice how this is actually less code (it's be even shorter if you just counted the number of occurrences, then updateMap dataset str = M.insertWith (+) str 1 dataset), and it separates the pure code from the impure.
In this case, you don't actually want to use forM_, because each step of the computation depends on the previous. It's preferred to write a recursive function that exits at a condition. If you so desired, you could also write loop as
loop :: Int -> IO (Map String Int)
loop n = go n M.empty
where
go 0 dataset = return dataset
go n dataset = getLine >>= go (n - 1) . updateMap dataset
Here I've compressed the body of the old loop into a single line and then put it inside go, this allows you to call it as
main :: IO ()
main = do
n <- fmap read getLine :: IO Int
dataset <- loop n
print dataset
This removes the need to know that you must pass in M.empty into loop for the first call, unless you have a use case to call loop multiple times on the same map.
Your problem is that Map.insert does not do what map.remove does in C++. Map.insert returns a new Map which has the element in it but you are simply throwing this new Map away. This is how nearly all Haskell data structures work, for instance the code:
main = do
let x = []
y = 5 : x
print x
prints the empty list []. The cons : operator does not destructively modify the empty list but returns a new list containing 5. Map.insert does the same but with Maps instead of lists.
First regarding your java code, you do not need to remove from the map before inserting a new value.
Regarding haskell, the language does not work the way you think it does : your let trick is not updating a value, everything is basically immutable in haskell.
Using only the basic getLine, one way to do it is to use recursion:
import qualified Data.Map as Map
type Dict = Map.Map String Int
makeDict ::Dict -> Int -> IO Dict
makeDict d remain = if remain == 0 then return d else do
l <- getLine
let newd = Map.insertWith (+) l 1 d
makeDict newd (remain - 1)
newDict count = makeDict Map.empty count

Why can't I compare result of lookup to Nothing in Haskell?

I have the following code:
import System.Environment
import System.Directory
import System.IO
import Data.List
dispatch :: [(String, [String] -> IO ())]
dispatch = [ ("add", add)
, ("view", view)
, ("remove", remove)
, ("bump", bump)
]
main = do
(command:args) <- getArgs
let result = lookup command dispatch
if result == Nothing then
errorExit
else do
let (Just action) = result
action args
errorExit :: IO ()
errorExit = do
putStrLn "Incorrect command"
add :: [String] -> IO ()
add [fileName, todoItem] = appendFile fileName (todoItem ++ "\n")
view :: [String] -> IO ()
view [fileName] = do
contents <- readFile fileName
let todoTasks = lines contents
numberedTasks = zipWith (\n line -> show n ++ " - " ++ line) [0..] todoTasks
putStr $ unlines numberedTasks
remove :: [String] -> IO ()
remove [fileName, numberString] = do
handle <- openFile fileName ReadMode
(tempName, tempHandle) <- openTempFile "." "temp"
contents <- hGetContents handle
let number = read numberString
todoTasks = lines contents
newTodoItems = delete (todoTasks !! number) todoTasks
hPutStr tempHandle $ unlines newTodoItems
hClose handle
hClose tempHandle
removeFile fileName
renameFile tempName fileName
bump :: [String] -> IO ()
bump [fileName, numberString] = do
handle <- openFile fileName ReadMode
(tempName, tempHandle) <- openTempFile "." "temp"
contents <- hGetContents handle
let number = read numberString
todoTasks = lines contents
bumpedItem = todoTasks !! number
newTodoItems = [bumpedItem] ++ delete bumpedItem todoTasks
hPutStr tempHandle $ unlines newTodoItems
hClose handle
hClose tempHandle
removeFile fileName
renameFile tempName fileName
Trying to compile it gives me the following error:
$ ghc --make todo
[1 of 1] Compiling Main ( todo.hs, todo.o )
todo.hs:16:15:
No instance for (Eq ([[Char]] -> IO ()))
arising from a use of `=='
Possible fix:
add an instance declaration for (Eq ([[Char]] -> IO ()))
In the expression: result == Nothing
In a stmt of a 'do' block:
if result == Nothing then
errorExit
else
do { let (Just action) = ...;
action args }
In the expression:
do { (command : args) <- getArgs;
let result = lookup command dispatch;
if result == Nothing then
errorExit
else
do { let ...;
.... } }
I don't get why is that since lookup returns Maybe a, which I'm surely can compare to Nothing.
The type of the (==) operator is Eq a => a -> a -> Bool. What this means is that you can only compare objects for equality if they're of a type which is an instance of Eq. And functions aren't comparable for equality: how would you write (==) :: (a -> b) -> (a -> b) -> Bool? There's no way to do it.1 And while clearly Nothing == Nothing and Just x /= Nothing, it's the case that Just x == Just y if and only if x == y; thus, there's no way to write (==) for Maybe a unless you can write (==) for a.
There best solution here is to use pattern matching. In general, I don't find myself using that many if statements in my Haskell code. You can instead write:
main = do (command:args) <- getArgs
case lookup command dispatch of
Just action -> action args
Nothing -> errorExit
This is better code for a couple of reasons. First, it's shorter, which is always nice. Second, while you simply can't use (==) here, suppose that dispatch instead held lists. The case statement remains just as efficient (constant time), but comparing Just x and Just y becomes very expensive. Second, you don't have to rebind result with let (Just action) = result; this makes the code shorter and doesn't introduce a potential pattern-match failure (which is bad, although you do know it can't fail here).
1:: In fact, it's impossible to write (==) while preserving referential transparency. In Haskell, f = (\x -> x + x) :: Integer -> Integer and g = (* 2) :: Integer -> Integer ought to be considered equal because f x = g x for all x :: Integer; however, proving that two functions are equal in this way is in general undecidable (since it requires enumerating an infinite number of inputs). And you can't just say that \x -> x + x only equals syntactically identical functions, because then you could distinguish f and g even though they do the same thing.
The Maybe a type has an Eq instance only if a has one - that's why you get No instance for (Eq ([[Char]] -> IO ())) (a function can't be compared to another function).
Maybe the maybe function is what you're looking for. I can't test this at the moment, but it should be something like this:
maybe errorExit (\action -> action args) result
That is, if result is Nothing, return errorExit, but if result is Just action, apply the lambda function on action.

Resources