Like many of you, I’ve been looking into migrating my libraries from Lwt to Eio to take advantage of OCaml 5’s direct-style concurrency. While the manual migration guides are excellent, I found myself making the same mechanical changes over and over—flattening binds, unwrapping promises, and rewriting maps.
So, I built lwt-to-eio, a tool that automates the boring parts of this transition.
What it does (The Magic)
It parses your OCaml source code and performs AST-level rewrites to transform monadic Lwt patterns into direct-style Eio code.
Input (Lwt):
let fetch_data id =
Lwt.bind (Db.get_user id) (fun user ->
Db.get_posts user.id >>= (fun posts ->
Lwt_list.map_p process posts
)
)
Output (Eio)
let fetch_data id =
let user = Lwt_eio.Promise.await_lwt (Db.get_user id) in
let posts = Lwt_eio.Promise.await_lwt (Db.get_posts user.id) in
Eio.Fiber.List.map process posts
Current Status & Help Wanted
This is currently an MVP. It handles the most common patterns I encountered (binds, map_p, sleep, return), but there is plenty of surface area left to cover.
I’m looking for contributors to help add rules for other common patterns. I’ve tagged a few issues as “Good First Issues” if anyone wants to dip their toes into ppxlib and AST rewriting:
Lwt.catch → try/with: Transforming monadic error handling to direct style exceptions.
Lwt_io support: Mapping legacy IO functions to Eio buffers.
Feedback, PRs, and “It broke on my file!” reports are all very welcome.
Hi everyone,
Like many of you, I’ve been looking into migrating my libraries from Lwt to Eio to take advantage of OCaml 5’s direct-style concurrency. While the manual migration guides are excellent, I found myself making the same mechanical changes over and over—flattening binds, unwrapping promises, and rewriting maps.
So, I built lwt-to-eio, a tool that automates the boring parts of this transition.
Repo: https://github.com/oug-t/lwt-to-eio
What it does (The Magic) It parses your OCaml source code and performs AST-level rewrites to transform monadic Lwt patterns into direct-style Eio code.
Input (Lwt):
let fetch_data id = Lwt.bind (Db.get_user id) (fun user -> Db.get_posts user.id >>= (fun posts -> Lwt_list.map_p process posts ) ) Output (Eio)
let fetch_data id = let user = Lwt_eio.Promise.await_lwt (Db.get_user id) in let posts = Lwt_eio.Promise.await_lwt (Db.get_posts user.id) in Eio.Fiber.List.map process posts Current Status & Help Wanted This is currently an MVP. It handles the most common patterns I encountered (binds, map_p, sleep, return), but there is plenty of surface area left to cover.
I’m looking for contributors to help add rules for other common patterns. I’ve tagged a few issues as “Good First Issues” if anyone wants to dip their toes into ppxlib and AST rewriting:
Lwt.catch → try/with: Transforming monadic error handling to direct style exceptions.
Lwt_io support: Mapping legacy IO functions to Eio buffers.
Feedback, PRs, and “It broke on my file!” reports are all very welcome.