[Haskell] Comportamento bizzarro, putStr vs putStrLn

kaspar1
Ciao :smt039
Scorporo un pezzo di codice, semplificandolo anche, da una programma inteso per terminale.

-- hask.hs

{-
  if you want to try that code by yourself,
  you may need to 'cabal install extra' first
-}
import Data.List.Extra (trim)

-- force the user to type something!
main :: IO ()
main = insertSomething >>= putStrLn . (">>> you\'ve typed: " ++)

insertSomething :: IO String
insertSomething = do putStr ">>> insert something: "
                     h . trim =<< getLine
  where h :: String -> IO String
        h xs = if null xs then insertSomething else return xs


$ runghc hask.hs
>>> insert something: something
>>> you've typed: something


Ok, interpretato fa quel che mi aspetto. Lo compilo (con successo)
$ ghc hask.hs

e lo provo
$ ./hask


niente, un rettangolino sta aspettando che io faccia qualcosa. Nel dubbio batto qualcosa
$ ./hask
something
>>> insert something: >>> you've typed: something

Che succede? Doveva chiedermi [tt]insert something:[/tt], invece no. Ha aspettato che io inserissi qualcosa, per poi farne la richiesta.

Allora provo ad usare [tt]putStrLn[/tt] al posto di [tt]putStr[/tt] in [tt]insertSomething[/tt] (perché non farlo?):

-- hask.hs

import Data.List.Extra (trim)

-- force the user to type something!
main :: IO ()
main = insertSomething >>= putStrLn . (">>> you\'ve typed: " ++)

insertSomething :: IO String
insertSomething = do putStrLn ">>> insert something: "
                     h . trim =<< getLine
  where h :: String -> IO String
        h xs = if null xs then insertSomething else return xs


Intepretato fa quel che mi aspetto (va a capo ogni volta, ma fa niente) e , sorpresa!, anche da compilato:
$ ./hask 
>>> insert something: 
ciao
>>> you've typed: ciao


Va bene, cosa non va in [tt]putStr[/tt]? O meglio: mi sfugge qualcosa?

Risposte
solaàl
A me fa esattamente quello che deve... Che versione di ghc? Usi stack? Che versione?

kaspar1
ghc ha versione 8.6.5, versione pacchettizzata da Debian. Tieni conto però che l'ultima versione stabile è 8.10.* e vuoi che non si siano accorti di [tt]putStr[/tt] prima? Può essere.

Bello sapere almeno che per qualcuno funziona.

Può essere anche, adesso l'ho visto, questo (almeno tre anni fa), ma non so cosa sia il buffering... (non sono un informatico, né sto studiando per diventarlo...)

Non uso stack ancora.

apatriarca
Sembra effettivamente un problema di buffering. Significa in pratica che l'output viene scritto nel terminale tutto insieme quando inserisci un carattere di a capo (o dopo un certo numero di caratteri). Viene usato perché la stampa su terminale ha un grosso costo indipendente dal numero di caratteri stampati e si riduce quindi questo costo facendolo più raramente. Tuttavia la richiesta di input da terminale di solito causa la scrittura di tutto quello che era in attesa.

Potrebbe essere un bug di ghc o di qualche altra libreria del tuo sistema.

kaspar1
"apatriarca":
Potrebbe essere un bug di ghc o di qualche altra libreria del tuo sistema.

Ho provato cercare qualche parola chiave, e in generale si consiglia di usare [tt]hFlush[/tt]:

import Data.List.Extra (trim)
import System.IO (hFlush, stdout)

main :: IO ()
main = putStrLn . (">>> you have typed: " ++) =<< typeSomething

typeSomething :: IO String
typeSomething = h . trim =<< getAnswerOf ">>> type something: "
  where
    h, getAnswerOf :: String -> IO String
    h xs = if null xs
              then typeSomething
              else return xs
    getAnswerOf request = do putStr request
                             hFlush stdout
                             getLine


@solaàl, tu che versione di ghc hai?

solaàl
The Glorious Glasgow Haskell Compilation System, version 8.10.2

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.