Skip to content

MVP: Segunda iteração #5

@yamadapc

Description

@yamadapc
  • Escrever primeiro batch de tutoriais (só vamos entender o que é preciso se implementarmos a ideia)
    • learnyouhaskell
    • learnyouworkhs
  • Mais type-safe
  • Interface melhor
    • O list-prompt precisa conseguir se renderizar propriamente independente do tamanho do terminal
  • i18n
  • Helpers para escrever tutoriais
    • verifica o output
    • roda IO e retorna um boolean
    • roda uma suite de testes do hspec contra uma função do módulo
    • roda uma suite de testes do hspec, tendo a execução/output do módulo fornecido de uma forma simples por outro helper

Tutoriais interativos de fato

Recentemente, brinquei com a ideia de rodar um GHCi como um sub-processo de um programa. Fiz isso para tentar fazer o ghci um pouco melhor. Acho que seria divertido poder lançar uma sessão do GHCi que fosse controlada pelo tutorial que está rodando. Tipo:

$ learnyouhaskell

  Bellow is a live REPL. Try pressing enter.

     ghci> putStrLn "something"<imagine-que-pressiona-enter>
     "something"

  Cool, that's what I wanted. Now what about doing a `map`?
  The type of map is:

     ghci> :t map
     map :: (a -> b) -> [a] -> [b]

  Try it yourself:

     ghci> <cursor-esta-aqui>

Imagine que temos algo como:

uiThread rc wc ewc = do
    _ <- forkIO $ forever $ do
        b <- atomically (readTChan wc)
        ByteString.putStr b
    _ <- forkIO $ forever $ do
        b <- atomically (readTChan ewc)
        ByteString.hPutStr stderr b
    loop
  where
    loop = do
        eof <- hIsEOF stdin
        unless eof $ do
            b <- ByteString.getLine
            atomically (writeTChan rc (b <> "\n"))
            loop

E menos sucetíveis a erros, claro. O que essa função faz é ler texto de dois canais e imprimir ele na tela. E aí podemos ter outra função:

ghciThread :: TChan ByteString -> TChan ByteString -> TChan ByteString -> IO ()
ghciThread rc wc ewc = do
    (inp, out, err, cph) <- ghciStreamingProcess
    readerTid <- forkIO $ chanSource readTChan rc `connect` inp
    outWriterTid <- forkIO $ out `connect` Conduit.ByteString.lines `connect` chanSink writeTChan wc
    errWriterTid <- forkIO $ err `connect` chanSink writeTChan ewc
    e <- waitForStreamingProcess cph
    return ()

Que publica o GHCi nesses canais; dependendo de:

chanSource read c = go
  where
    go = do
        x <- liftIO (atomically (read c))
        Conduit.yield x
        go

chanSink write c = Conduit.List.mapM_ $ liftIO . atomically . write c

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions