You can't do that, at least not directly. The problem is that Costring
can be infinite in size, while String
s must be finite.
Imagine running the program as prog < /dev/zero
, what should happen? The reverse
function can produce the first element only after reaching the end of the input list and that may never happen.
We need to express the fact that converting a Costring
to String
can fail. One way to do it is to use the partiality monad. Let's take a look at the definition:
data _⊥ {a} (A : Set a) : Set a where
now : (x : A) → A ⊥
later : (x : ∞ (A ⊥)) → A ⊥
So, we can either have a value of type A
right now
, or we need to wait for later
. But notice the ∞
symbol: that means we can actually wait forever (as in there can be infinite number of later
constructors).
I'll merge the conversion and reversing into one function. Imports first:
open import Category.Monad.Partiality
open import Coinduction
open import Data.Char
open import Data.Colist
using ([]; _∷_)
open import Data.List
using ([]; _∷_; List)
open import Data.String
open import Data.Unit
open import IO
Now, the type of our reverse
function should mention that we take a Costring
as an input but also that returning a String
may fail. The implementation is then fairly simple, it's the usual reverse with accumulator:
reverse : Costring → String ⊥
reverse = go []
where
go : List Char → Costring → String ⊥
go acc [] = now (fromList acc)
go acc (x ∷ xs) = later (♯ go (x ∷ acc) (♭ xs))
However, we can print a String
, but not String ⊥
! That's where IO
helps: we can interpret the later
constructors as "do nothing" and if we find now
constructor, we can putStrLn
the String
it contains.
putStrLn⊥ : String ⊥ → IO ⊤
putStrLn⊥ (now s) = putStrLn s
putStrLn⊥ (later s) = ♯ return tt >> ♯ putStrLn⊥ (♭ s)
Notice that I use the IO
from IO
module, not the one from IO.Primitive
. This is basically a layer built on the postulates, so it's a bit nicer. But if you want to use getLine
with this, you have to write:
import IO.Primitive as Prim
postulate
primGetLine : Prim.IO Costring
{-# COMPILED primGetLine getLine #-}
getLine : IO Costring
getLine = lift primGetLine
And finally, we can write the main
function:
main = run (♯ getLine >>= λ c → ♯ putStrLn⊥ (reverse c))
Compiling this program using C-c C-x C-c
and then running it, we get the expected:
$ cat test
hello world
$ prog < test
dlrow olleh