package ppx_partial

  1. Overview
  2. Docs
Syntax for a partial application of functions that omits any argument

Install

Dune Dependency

Authors

Maintainers

Sources

ppx_partial-1.0.tbz
sha256=98f5540ea530fc4aebb555e2063848bd6aca84eb72f7fb8cd8bfdc45c4650416
sha512=f5fc43aed73a92da585548aca41c2207989e4d2515a74a0a12698ae0e6dbdfa8d3f832b3b9f2e747c90531bce8a34b5c68d994ed3bfd38827d67c0c890091093

Description

This provides a syntax f e1 __ e3 that's means (fun x -> f e1 x e3), except that e1 and e3 are evaluated just once.

This can be convenient in pipelines or to build arguments for List.map or any places that need single-argument functions.

As a slight generalization, __.record_field and Sum_constructor __ allow shortening (fun x -> x.record_field) and (fun x -> Sum_constructor x).

Tags

syntax ppx

Published: 29 Jun 2024

README

What it does

ppx_partial is a preprocessor that makes it possible to do partial applications that omit any parameter of a function, rather than necessarily a suffix of unlabelled arguments with currying:

something_that_returns_a_string ()
|> Base.String.drop_suffix __ 1
|> Stdio.Out_channel.write_all "/tmp/z" ~data:__

is turned into:

something_that_returns_a_string ()
|> (fun x -> Base.String.drop_prefix x 1)
|> (fun x -> Stdio.Out_channel.write_all "/tmp/z" ~data:x)

In the general case, the ppx ensures that all parameters are executed exactly once, just like with a regular partial application. For instance, these two expressions have the exact same performance :

List.filter (Re.execp (Re.compile re) __) l
List.filter (Re.execp (Re.compile re)) l

As a slight generalization, field accesses and sum constructors are allowed: List.map __.field l, List.map (Some __) l.

As an other slight generalization, it is possible to omit the function instead of an argument: Option.iter o ~f:(__ ()) which means Option.iter o ~f:(fun f -> f ()).

What it doesn't do

This is not a general lighter syntax for short anonymous functions. If you want a lightweight syntax for (fun x -> f (g x)) or (fun x -> x * 2 + 1), this ppx isn't providing such things.

Why

The purpose is simply convenience. To be more specific :

  • __.field and Some __ should be self-explanatory.

  • there is a tension between 1) easy pipelining (meaning "main parameter" last) 2) t parameter first consistently 3) no excessive labelling of parameters: you can't get all three consistently.

    • Base.List.take list int is a function that picks 2) and 3) but drops 1).

    • Base.Or_error.tag error ~tag is a function that picks 1) and 2) but drops 3).

    • Stdlib.Map.add key value map is a function that picks 1) and 3) but drops 2).

    ppx_partial provides 1) for every parameter of every function, thus function signatures only have to provide 2) and 3).

  • partial application of some infix operators can be very misleading. List.filter ((>) 0) can easily be read as List.filter (fun -> x > 0), when it actually means List.filter (fun x -> 0 > x). Writing List.filter (__ > 0) is clearer.

  • Very occasionaly, this can be used to drop optional parameters by "eta-expansion", like so:

       match flavor with
       | `Xml -> Markup.parse_xml __ (* wouldn't type without __, due to optional parameters *)
       | `Html -> Markup.parse_html __
    

    or it can be used to omit a parameter that's not the usual one, say List.iter __ l or List.iter ~f:__ l.

Dependencies (3)

  1. dune >= "3.15"
  2. ocaml >= "4.14.0"
  3. ppxlib >= "0.32.1"

Dev Dependencies (5)

  1. odoc with-doc
  2. ppx_assert with-test
  3. ppx_inline_test with-test
  4. ppx_pipebang with-test
  5. base with-test

Used by

None

Conflicts

None

OCaml

Innovation. Community. Security.