As they should be.
I object to doing what a computer can do for me (in programming), and manually creating separate versions of functions that are identical up to async absolutely falls into that category.
I object to doing what a computer can do for me (in programming), and manually creating separate versions of functions that are identical up to async absolutely falls into that category.
transformFile = do {
x <- readFile(...)
y = process(x)
z <- writeFile(...)
}
is the equivalent of something like: async transformFile = {
x = await readFile(...)
y = process(x)
z = await writeFile(...)
}
In Haskell you write exactly the same code when readFile and writeFile are async, or when they're polymorphically async-or-not, your function will just implicitly be as polymorphic as it possibly can be based on the functions it's calling.In Scala you need an explicit type parameter if you want to be polymorphic:
def transformFile = for {
x <- readFile(...)
y = process(x)
z <- writeFile(...)
} yield ()
def transformFile[F[_]: Monad] = for {
x <- readFile(...)
y = process(x)
z <- writeFile(...)
} yield ()
The first example is always async, the second example is polymorphic (it's calling readFile[F] and writeFile[F], but those get inferred).