Search code examples
purescript

PureScript - Replace `launchAff_` with `launchAff`


Consider the following working code example, that uses launchAff_ to copy a JSON file:

module Main where

import Prelude 
import Effect (Effect)
import Effect.Aff (Aff, launchAff_)
import Node.Encoding (Encoding(..))
import Node.FS.Aff (readTextFile, writeTextFile)
import Node.Path (FilePath)

duplicateCustomerData :: FilePath -> FilePath -> Aff Unit

duplicateCustomerData filePath1 filePath2 = do
  customer_data <- readTextFile UTF8 filePath1
  writeTextFile UTF8 filePath2 customer_data

main :: Effect Unit
main = launchAff_ do
  duplicateCustomerData "database/customer-1.json" "database/customer-2.json"

However, if the main function is changed to use launchAff (without the underscore) like so

main :: Effect Unit
main = launchAff do
  duplicateCustomerData "database/customer-1.json" "database/customer-2.json"

The following error is thrown:

  Could not match type
  
    Fiber Unit
  
  with type
        
    Unit

Thus,

  1. What is a fiber unit?
  2. What is the use case for this fiber unit? Is it meant to be discarded? What does it represent?
  3. Why are there two launchAff functions?

Solution

  • Fiber represents a running async computation.

    The difference between Fiber and Aff is the "running" part. Aff is not an async computation that is running, but rather a way to start an async computation. It's not started until you bind it in a larger computation. And conversely, you can start the same Aff multiple times.

    Fiber, on the other hand, is an async computation that has already been started, it's already in progress. You can kill it via killFiber or you can wait for it to complete via joinFiber, and some other things. See the docs.

    And now that we know that (1) Aff is a way to start an async computation, and (2) Fiber is an already-running async computation, it should become obvious that a Fiber would be the result of starting an Aff. Which is exactly what you observe: launchAff takes an Aff and returns a Fiber.

    But sometimes (in my own experience - most times) we don't actually need the resulting Fiber. There is nothing we're going to do with it. For those cases, there is a convenience shortcut - launchAff_. It does the same thing as launchAff, but throws away the resulting Fiber. See it for yourself in the source code.

    Adding an underscore at the end to mean "returns unit" is a common pattern. For example, there are for and for_, there are traverse and traverse_, there are runAff and runAff_.