2

Given this context:

open import IO
open import Data.String
open import Data.Unit
open import Coinduction

postulate
  A : Set
  f : String → A
  g₁ g₂ : A → String

let's say I want to implement something like

foo : IO ⊤
foo = ♯ readFiniteFile "input.txt" >>= \s →
      ♯ (♯ putStrLn (g₁ (f s)) >>
      ♯ putStrLn (g₂ (f s)))

by let-binding the intermediate result f s. I was hoping this would work:

foo₁ : IO ⊤
foo₁ = ♯ readFiniteFile "input.txt" >>= \s →
       let x = f s in
       ♯ (♯ putStrLn (g₁ x) >>
       ♯ putStrLn (g₂ x))

but this fails with

Not implemented: coinductive constructor in the scope of a let-bound variable

so I tried moving out the :

foo₂ : IO ⊤
foo₂ = ♯ readFiniteFile "input.txt" >>= \s →
       ♯ (let x = f s in
       ♯ putStrLn (g₁ x) >>
       ♯ putStrLn (g₂ x))

same problem as before.

I managed to get around this by just lifting out the ening step:

_>>′_ : ∀ {a} {A B : Set a} → IO A → IO B → IO B
m >>′ m′ = ♯ m >> ♯ m′

foo₂ : IO ⊤
foo₂ = ♯ readFiniteFile "input.txt" >>= \s →
       ♯ let x = f s in
       putStrLn (g₁ x) >>′ putStrLn (g₂ x)

but why does that work if the "inlined" version doesn't?

Cactus
  • 27,075
  • 9
  • 69
  • 149
  • 2
    I had a quick look at projects I have involving `IO` and I ended up doing the same sort of thing. And they work alright. Ulf's [IO](https://github.com/UlfNorell/agda-prelude/blob/master/src/Prelude/IO.agda) might be nicer to work with: it is a traditional monad rather than a coinductive type (but it also means that you need to assume that all the files you deal with are finite). – gallais Mar 18 '16 at 10:25

1 Answers1

1

FYI, this problem was a long standing one and as I was having a look at it today, I noticed that it had been fixed just a few days before you asked your question. The fix is part of the currently released version (version 2.5.1.1).

gallais
  • 11,823
  • 2
  • 30
  • 63