113.24.00
This commit is contained in:
commit
f255c375a0
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
_build/
|
||||||
|
/setup.data
|
||||||
|
/setup.log
|
||||||
|
/*.exe
|
||||||
|
/*.docdir
|
||||||
|
/*.native
|
||||||
|
/*.byte
|
12
INRIA-DISCLAIMER.txt
Normal file
12
INRIA-DISCLAIMER.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
THIS SOFTWARE IS PROVIDED BY INRIA AND CONTRIBUTORS "AS IS" AND ANY
|
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INRIA OR ITS CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||||
|
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||||
|
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||||
|
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
202
LICENSE.txt
Normal file
202
LICENSE.txt
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
8
META.ab
Normal file
8
META.ab
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
version = "$(pkg_version)"
|
||||||
|
description = "Monadic let-bindings"
|
||||||
|
requires = "ppx_core ppx_driver"
|
||||||
|
archive(ppx_driver, byte ) = "ppx_let.cma"
|
||||||
|
archive(ppx_driver, native ) = "ppx_let.cmxa"
|
||||||
|
archive(ppx_driver, native, plugin) = "ppx_let.cmxs"
|
||||||
|
exists_if = "ppx_let.cma"
|
||||||
|
ppx(-ppx_driver) = "./ppx"
|
68
Makefile
Normal file
68
Makefile
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
# Generic Makefile for oasis project
|
||||||
|
|
||||||
|
SETUP := setup.exe
|
||||||
|
NAME := ppx_let
|
||||||
|
PREFIX = $(shell grep ^prefix= setup.data | cut -d\" -f 2)
|
||||||
|
|
||||||
|
# Default rule
|
||||||
|
default: build
|
||||||
|
|
||||||
|
setup.exe: _oasis setup.ml
|
||||||
|
ocamlfind ocamlopt -o $@ -linkpkg -package ocamlbuild,oasis.dynrun setup.ml || \
|
||||||
|
ocamlfind ocamlc -o $@ -linkpkg -package ocamlbuild,oasis.dynrun setup.ml || true
|
||||||
|
for f in setup.*; do [ $$f = $@ -o $$f = setup.ml ] || rm -f $$f; done
|
||||||
|
|
||||||
|
build: $(SETUP) setup.data
|
||||||
|
./$(SETUP) -build $(BUILDFLAGS)
|
||||||
|
$(MAKE) $(NAME).install
|
||||||
|
|
||||||
|
doc: $(SETUP) setup.data build
|
||||||
|
./$(SETUP) -doc $(DOCFLAGS)
|
||||||
|
|
||||||
|
test: $(SETUP) setup.data build
|
||||||
|
./$(SETUP) -test $(TESTFLAGS)
|
||||||
|
|
||||||
|
all: $(SETUP)
|
||||||
|
./$(SETUP) -all $(ALLFLAGS)
|
||||||
|
$(MAKE) $(NAME).install
|
||||||
|
|
||||||
|
$(NAME).install: js-utils/gen_install.ml setup.log setup.data
|
||||||
|
ocaml -I js-utils js-utils/gen_install.ml
|
||||||
|
|
||||||
|
install: $(NAME).install
|
||||||
|
opam-installer -i --prefix $(PREFIX) $(NAME).install
|
||||||
|
|
||||||
|
uninstall: $(NAME).install
|
||||||
|
opam-installer -u --prefix $(PREFIX) $(NAME).install
|
||||||
|
|
||||||
|
reinstall: $(NAME).install
|
||||||
|
opam-installer -u --prefix $(PREFIX) $(NAME).install &> /dev/null || true
|
||||||
|
opam-installer -i --prefix $(PREFIX) $(NAME).install
|
||||||
|
|
||||||
|
bin.tar.gz: $(NAME).install
|
||||||
|
rm -rf _install
|
||||||
|
mkdir _install
|
||||||
|
opam-installer -i --prefix _install $(NAME).install
|
||||||
|
tar czf bin.tar.gz -C _install .
|
||||||
|
rm -rf _install
|
||||||
|
|
||||||
|
bin.lzo: $(NAME).install
|
||||||
|
rm -rf _install
|
||||||
|
mkdir _install
|
||||||
|
opam-installer -i --prefix _install $(NAME).install
|
||||||
|
cd _install && lzop -1 -P -o ../bin.lzo `find . -type f`
|
||||||
|
rm -rf _install
|
||||||
|
|
||||||
|
clean: $(SETUP)
|
||||||
|
./$(SETUP) -clean $(CLEANFLAGS)
|
||||||
|
|
||||||
|
distclean: $(SETUP)
|
||||||
|
./$(SETUP) -distclean $(DISTCLEANFLAGS)
|
||||||
|
|
||||||
|
configure: $(SETUP)
|
||||||
|
./$(SETUP) -configure $(CONFIGUREFLAGS)
|
||||||
|
|
||||||
|
setup.data: $(SETUP)
|
||||||
|
./$(SETUP) -configure $(CONFIGUREFLAGS)
|
||||||
|
|
||||||
|
.PHONY: default build doc test all install uninstall reinstall clean distclean configure
|
156
README.md
Normal file
156
README.md
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
A ppx rewriter for monadic and applicative let bindings and match statements.
|
||||||
|
|
||||||
|
Overview
|
||||||
|
--------
|
||||||
|
|
||||||
|
The aim of this rewriter is to make monadic and applicative code look
|
||||||
|
nicer by writing custom binders the same way that we normally bind
|
||||||
|
variables. In OCaml, the common way to bind the result of a
|
||||||
|
computation to a variable is:
|
||||||
|
|
||||||
|
```ocaml
|
||||||
|
let VAR = EXPR in BODY
|
||||||
|
```
|
||||||
|
|
||||||
|
ppx\_let simply adds two new binders: `let%bind` and
|
||||||
|
`let%map`. These are rewritten into calls to the `bind` and
|
||||||
|
`map` functions respectively. These functions are expected to have
|
||||||
|
|
||||||
|
```ocaml
|
||||||
|
val map : 'a t -> f:('a -> 'b) -> 'b t
|
||||||
|
val bind : 'a t -> ('a -> 'b t) -> 'b t
|
||||||
|
```
|
||||||
|
|
||||||
|
for some type `t`, as one might expect.
|
||||||
|
|
||||||
|
These functions are to be provided by the user, and are generally
|
||||||
|
expected to be part of the signatures of monads and applicatives
|
||||||
|
modules. This is the case for all monads and applicatives defined by
|
||||||
|
the Jane Street's Core suite of libraries. (see the section below on
|
||||||
|
getting the right names into scope).
|
||||||
|
|
||||||
|
### Parallel bindings
|
||||||
|
|
||||||
|
ppx\_monad understands parallel bindings as well. i.e.:
|
||||||
|
|
||||||
|
```ocaml
|
||||||
|
let%bind VAR1 = EXPR1 and VAR2 = EXPR2 and VAR3 = EXPR3 in BODY
|
||||||
|
```
|
||||||
|
|
||||||
|
The `and` keyword is seen as a binding combination operator. To do so
|
||||||
|
it expects the presence of a `both` function, that lifts the OCaml
|
||||||
|
pair operation to the type `t` in question:
|
||||||
|
|
||||||
|
```ocaml
|
||||||
|
val both : 'a t -> 'b t -> ('a * 'b) t
|
||||||
|
```
|
||||||
|
|
||||||
|
### Match statements
|
||||||
|
|
||||||
|
We found that this form was quite useful for match statements as
|
||||||
|
well. So for convenience ppx\_monad also accept `%bind` and `%map` on
|
||||||
|
the `match` keyword. Morally `match%bind expr with cases` is seen as
|
||||||
|
`let%bind x = expr in match x with cases`.
|
||||||
|
|
||||||
|
Syntactic forms and actual rewriting
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
|
`ppx_let` adds four syntactic forms
|
||||||
|
|
||||||
|
```ocaml
|
||||||
|
let%bind P = M in E
|
||||||
|
|
||||||
|
let%map P = M in E
|
||||||
|
|
||||||
|
match%bind M with P1 -> E1 | P2 -> E2 | ...
|
||||||
|
|
||||||
|
match%map M with P1 -> E1 | P2 -> E2 | ...
|
||||||
|
```
|
||||||
|
|
||||||
|
that expand into
|
||||||
|
|
||||||
|
```ocaml
|
||||||
|
bind M (fun P -> E)
|
||||||
|
|
||||||
|
map M (fun P -> E)
|
||||||
|
|
||||||
|
bind M (function P1 -> E1 | P2 -> E2 | ...)
|
||||||
|
|
||||||
|
map M (function P1 -> E1 | P2 -> E2 | ...)
|
||||||
|
```
|
||||||
|
|
||||||
|
respectively.
|
||||||
|
|
||||||
|
As with `let`, `let%bind` and `let%map` also support multiple
|
||||||
|
*parallel* bindings via the `and` keyword:
|
||||||
|
|
||||||
|
```ocaml
|
||||||
|
let%bind P1 = M1 and P2 = M2 and P3 = M3 and P4 = M4 in E
|
||||||
|
|
||||||
|
let%map P1 = M1 and P2 = M2 and P3 = M3 and P4 = M4 in E
|
||||||
|
```
|
||||||
|
|
||||||
|
that expand into
|
||||||
|
|
||||||
|
```ocaml
|
||||||
|
let x1 = M1 and x2 = M2 and x3 = M3 and x4 = M4 in
|
||||||
|
bind
|
||||||
|
(both x1 (both x2 (both x3 x4)))
|
||||||
|
(fun (P1, (P2, (P3, P4))) -> E)
|
||||||
|
|
||||||
|
let x1 = M1 and x2 = M2 and x3 = M3 and x4 = M4 in
|
||||||
|
map
|
||||||
|
(both x1 (both x2 (both x3 x4)))
|
||||||
|
(fun (P1, (P2, (P3, P4))) -> E)
|
||||||
|
```
|
||||||
|
|
||||||
|
respectively. (Instead of `x1`, `x2`, ... ppx\_monad uses
|
||||||
|
variable names that are unlikely to clash with other names)
|
||||||
|
|
||||||
|
As with `let`, names introduced by left-hand sides of the let bindings
|
||||||
|
are not available in subsequent right-hand sides of the same sequence.
|
||||||
|
|
||||||
|
Getting the right names in scope
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
The description of how the `%bind` and `%map` syntax extensions expand
|
||||||
|
left out the fact that the names `bind`, `map`, `both`, and `return`
|
||||||
|
are not used directly, but rather qualified by `Let_syntax`. For
|
||||||
|
example, we use `Let_syntax.bind` rather than merely `bind`. This
|
||||||
|
means one just needs to get a properly loaded `Let_syntax` module in
|
||||||
|
scope to use `%bind` and `%map`.
|
||||||
|
|
||||||
|
For monads, `Core.Std.Monad.Make` produces a submodule `Let_syntax` of
|
||||||
|
the appropriate form.
|
||||||
|
|
||||||
|
For applicatives. The convention for these modules is to have a
|
||||||
|
submodule `Let_syntax` of the form
|
||||||
|
|
||||||
|
```ocaml
|
||||||
|
module Let_syntax : sig
|
||||||
|
val return : 'a -> 'a t
|
||||||
|
val map : 'a t -> f:('a -> 'b) -> 'b t
|
||||||
|
val both : 'a t -> 'b t -> ('a * 'b) t
|
||||||
|
module Open_on_rhs : << some signature >>
|
||||||
|
module Open_in_body : << some signature >>
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
The `Open_on_rhs` and `Open_in_body` submodules are used by variants
|
||||||
|
of `%map` and `%bind` called `%map_open` and `%bind_open`.
|
||||||
|
|
||||||
|
The `Open_on_rhs` submodule is locally opened on the right hand sides
|
||||||
|
of the rewritten let bindings in `%map_open` and `%bind_open`
|
||||||
|
expressions. This is useful when programming with applicatives, which
|
||||||
|
operate in a staged manner where the operators used to construct the
|
||||||
|
applicatives are distinct from the operators used to manipulate the
|
||||||
|
values those applicatives produce. For monads, `Open_on_rhs` contains
|
||||||
|
`return`.
|
||||||
|
|
||||||
|
The `Open_in_body` submodule is locally opened in the body of either a
|
||||||
|
`let%map_open` or `let%bind_open`. It is often empty for
|
||||||
|
applicatives. For monads in `Core`, it contains `return`.
|
||||||
|
|
||||||
|
For `match%map_open` and `match%bind_open` expressions, `Open_on_rhs`
|
||||||
|
is opened for the expression being matched on, and `Open_in_body` is
|
||||||
|
opened in the body of each pattern match clause.
|
18
THIRD-PARTY.txt
Normal file
18
THIRD-PARTY.txt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
The repository contains 3rd-party code in the following locations and
|
||||||
|
under the following licenses:
|
||||||
|
|
||||||
|
- type_conv, sexplib and bin_prot: based on Tywith, by Martin
|
||||||
|
Sandin. License can be found in base/sexplib/LICENSE-Tywith.txt,
|
||||||
|
base/type_conv/LICENSE-Tywith.txt, and base/bin_prot/LICENSE-Tywith.txt.
|
||||||
|
|
||||||
|
- Core's implementation of union-find: based on an implementation by
|
||||||
|
Henry Matthew Fluet, Suresh Jagannathan, and Stephen Weeks. License
|
||||||
|
can be found in base/core/MLton-license.
|
||||||
|
|
||||||
|
- Various Core libraries are based on INRIA's OCaml
|
||||||
|
distribution. Relicensed under Apache 2.0, as permitted under the
|
||||||
|
Caml License for Consortium members:
|
||||||
|
|
||||||
|
http://caml.inria.fr/consortium/license.en.html
|
||||||
|
|
||||||
|
See also the disclaimer INRIA-DISCLAIMER.txt.
|
33
_oasis
Normal file
33
_oasis
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
OASISFormat: 0.4
|
||||||
|
OCamlVersion: >= 4.02.3
|
||||||
|
FindlibVersion: >= 1.3.2
|
||||||
|
Name: ppx_let
|
||||||
|
Version: 113.24.00
|
||||||
|
Synopsis: Monadic let-bindings
|
||||||
|
Authors: Jane Street Group, LLC <opensource@janestreet.com>
|
||||||
|
Copyrights: (C) 2015-2016 Jane Street Group LLC <opensource@janestreet.com>
|
||||||
|
Maintainers: Jane Street Group, LLC <opensource@janestreet.com>
|
||||||
|
License: Apache-2.0
|
||||||
|
LicenseFile: LICENSE.txt
|
||||||
|
Homepage: https://github.com/janestreet/ppx_let
|
||||||
|
Plugins: StdFiles (0.3), DevFiles (0.3), META (0.3)
|
||||||
|
XStdFilesAUTHORS: false
|
||||||
|
XStdFilesREADME: false
|
||||||
|
BuildTools: ocamlbuild
|
||||||
|
FilesAB: META.ab
|
||||||
|
Description:
|
||||||
|
Part of the Jane Street's PPX rewriters collection.
|
||||||
|
|
||||||
|
Library ppx_let
|
||||||
|
Path: src
|
||||||
|
Pack: false
|
||||||
|
Modules: Ppx_let
|
||||||
|
BuildDepends: ppx_core,
|
||||||
|
ppx_driver
|
||||||
|
|
||||||
|
Executable ppx
|
||||||
|
Path: as_ppx
|
||||||
|
MainIs: ppx.ml
|
||||||
|
CompiledObject: best
|
||||||
|
BuildDepends: ppx_let,
|
||||||
|
ppx_driver
|
8
_tags
Normal file
8
_tags
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<**/*.ml{,i}>: warn(-40), no_alias_deps
|
||||||
|
<**/*>: thread
|
||||||
|
# This prevents the implicit addition of -ppx options by ocamlfind
|
||||||
|
<**/*.ml{,i}>: predicate(ppx_driver)
|
||||||
|
<as_ppx/ppx.{byte,native}>: predicate(ppx_driver)
|
||||||
|
<src/*>: linkall
|
||||||
|
# OASIS_START
|
||||||
|
# OASIS_STOP
|
1
as_ppx/ppx.ml
Normal file
1
as_ppx/ppx.ml
Normal file
@ -0,0 +1 @@
|
|||||||
|
Ppx_driver.run_as_ppx_rewriter ()
|
5
configure
vendored
Executable file
5
configure
vendored
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# OASIS_START
|
||||||
|
make configure CONFIGUREFLAGS="$*"
|
||||||
|
# OASIS_STOP
|
2
descr
Normal file
2
descr
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
Monadic let-bindings
|
||||||
|
Part of the Jane Street's PPX rewriters collection.
|
102
js-utils/gen_install.ml
Normal file
102
js-utils/gen_install.ml
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
(* Generate <package>.install from setup.log *)
|
||||||
|
|
||||||
|
#use "install_tags.ml"
|
||||||
|
|
||||||
|
module String_map = Map.Make(String)
|
||||||
|
let string_map_of_list =
|
||||||
|
List.fold_left
|
||||||
|
(fun acc (k, v) ->
|
||||||
|
assert (not (String_map.mem k acc));
|
||||||
|
String_map.add k v acc)
|
||||||
|
String_map.empty
|
||||||
|
|
||||||
|
let lines_of_file fn =
|
||||||
|
let ic = open_in fn in
|
||||||
|
let rec loop acc =
|
||||||
|
match input_line ic with
|
||||||
|
| exception End_of_file ->
|
||||||
|
close_in ic;
|
||||||
|
List.rev acc
|
||||||
|
| line ->
|
||||||
|
loop (line :: acc)
|
||||||
|
in
|
||||||
|
loop []
|
||||||
|
|
||||||
|
let read_setup_log () =
|
||||||
|
lines_of_file "setup.log"
|
||||||
|
|> List.map (fun line -> Scanf.sscanf line "%S %S" (fun tag arg -> (tag, arg)))
|
||||||
|
|
||||||
|
let read_setup_data () =
|
||||||
|
lines_of_file "setup.data"
|
||||||
|
|> List.map (fun line -> Scanf.sscanf line "%[^=]=%S" (fun k v -> (k, v)))
|
||||||
|
|
||||||
|
let remove_cwd =
|
||||||
|
let prefix = Sys.getcwd () ^ "/" in
|
||||||
|
let len_prefix = String.length prefix in
|
||||||
|
fun fn ->
|
||||||
|
let len = String.length fn in
|
||||||
|
if len >= len_prefix && String.sub fn 0 len_prefix = prefix then
|
||||||
|
String.sub fn len_prefix (len - len_prefix)
|
||||||
|
else
|
||||||
|
fn
|
||||||
|
|
||||||
|
let gen_section oc name files =
|
||||||
|
let pr fmt = Printf.fprintf oc (fmt ^^ "\n") in
|
||||||
|
pr "%s: [" name;
|
||||||
|
List.iter
|
||||||
|
(fun (src, dst) ->
|
||||||
|
let src = remove_cwd src in
|
||||||
|
let dst =
|
||||||
|
match dst with
|
||||||
|
| None -> Filename.basename src
|
||||||
|
| Some fn -> fn
|
||||||
|
in
|
||||||
|
if src = dst then
|
||||||
|
pr " %S" src
|
||||||
|
else
|
||||||
|
pr " %S {%S}" src dst)
|
||||||
|
files;
|
||||||
|
pr "]"
|
||||||
|
|
||||||
|
let rec filter_log tags log acc =
|
||||||
|
match log with
|
||||||
|
| [] -> acc
|
||||||
|
| (tag, fname) :: rest ->
|
||||||
|
match String_map.find tag tags with
|
||||||
|
| exception Not_found -> filter_log tags rest acc
|
||||||
|
| dst -> filter_log tags rest ((fname, dst) :: acc)
|
||||||
|
|
||||||
|
let () =
|
||||||
|
let log = read_setup_log () in
|
||||||
|
let setup_data = read_setup_data () in
|
||||||
|
let ext_dll =
|
||||||
|
match List.assoc "ext_dll" setup_data with
|
||||||
|
| ext -> ext
|
||||||
|
| exception Not_found -> ".so"
|
||||||
|
in
|
||||||
|
let merge name files map =
|
||||||
|
match String_map.find name map with
|
||||||
|
| files' -> String_map.add name (files @ files') map
|
||||||
|
| exception Not_found -> String_map.add name files map
|
||||||
|
in
|
||||||
|
let sections =
|
||||||
|
List.fold_left
|
||||||
|
(fun acc (name, tags, extra_files) ->
|
||||||
|
let tags = string_map_of_list tags in
|
||||||
|
let files = filter_log tags log [] @ extra_files in
|
||||||
|
if name = "lib" then
|
||||||
|
let stubs, others =
|
||||||
|
List.partition
|
||||||
|
(fun (fn, _) -> Filename.check_suffix fn ext_dll)
|
||||||
|
files
|
||||||
|
in
|
||||||
|
merge "lib" others (merge "stublibs" stubs acc)
|
||||||
|
else
|
||||||
|
merge name files acc)
|
||||||
|
String_map.empty sections
|
||||||
|
|> String_map.bindings
|
||||||
|
|> List.filter (fun (_, l) -> l <> [])
|
||||||
|
in
|
||||||
|
let oc = open_out (package_name ^ ".install") in
|
||||||
|
List.iter (fun (name, files) -> gen_section oc name files) sections;
|
||||||
|
close_out oc
|
13
js-utils/install_tags.ml
Normal file
13
js-utils/install_tags.ml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
let package_name = "ppx_let"
|
||||||
|
|
||||||
|
let sections =
|
||||||
|
[ ("lib",
|
||||||
|
[ ("built_lib_ppx_let", None)
|
||||||
|
],
|
||||||
|
[ ("META", None)
|
||||||
|
])
|
||||||
|
; ("libexec",
|
||||||
|
[ ("built_exec_ppx", Some "ppx")
|
||||||
|
],
|
||||||
|
[])
|
||||||
|
]
|
29
myocamlbuild.ml
Normal file
29
myocamlbuild.ml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
(* OASIS_START *)
|
||||||
|
(* OASIS_STOP *)
|
||||||
|
# 3 "myocamlbuild.ml"
|
||||||
|
|
||||||
|
(* Temporary hacks *)
|
||||||
|
let js_hacks = function
|
||||||
|
| After_rules ->
|
||||||
|
rule "Generate a cmxs from a cmxa"
|
||||||
|
~dep:"%.cmxa"
|
||||||
|
~prod:"%.cmxs"
|
||||||
|
~insert:`top
|
||||||
|
(fun env _ ->
|
||||||
|
Cmd (S [ !Options.ocamlopt
|
||||||
|
; A "-shared"
|
||||||
|
; A "-linkall"
|
||||||
|
; A "-I"; A (Pathname.dirname (env "%"))
|
||||||
|
; A (env "%.cmxa")
|
||||||
|
; A "-o"
|
||||||
|
; A (env "%.cmxs")
|
||||||
|
]));
|
||||||
|
|
||||||
|
(* Pass -predicates to ocamldep *)
|
||||||
|
pflag ["ocaml"; "ocamldep"] "predicate" (fun s -> S [A "-predicates"; A s])
|
||||||
|
| _ -> ()
|
||||||
|
|
||||||
|
let () =
|
||||||
|
Ocamlbuild_plugin.dispatch (fun hook ->
|
||||||
|
js_hacks hook;
|
||||||
|
dispatch_default hook)
|
19
opam
Normal file
19
opam
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
opam-version: "1.2"
|
||||||
|
maintainer: "opensource@janestreet.com"
|
||||||
|
authors: ["Jane Street Group, LLC <opensource@janestreet.com>"]
|
||||||
|
homepage: "https://github.com/janestreet/ppx_let"
|
||||||
|
bug-reports: "https://github.com/janestreet/ppx_let/issues"
|
||||||
|
dev-repo: "https://github.com/janestreet/ppx_let.git"
|
||||||
|
license: "Apache-2.0"
|
||||||
|
build: [
|
||||||
|
["./configure" "--prefix" prefix]
|
||||||
|
[make]
|
||||||
|
]
|
||||||
|
depends: [
|
||||||
|
"ocamlbuild" {build}
|
||||||
|
"oasis" {build & >= "0.4"}
|
||||||
|
"ocamlfind" {build & >= "1.3.2"}
|
||||||
|
"ppx_core"
|
||||||
|
"ppx_driver"
|
||||||
|
]
|
||||||
|
available: [ ocaml-version >= "4.02.3" ]
|
6
setup.ml
Normal file
6
setup.ml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
(* OASIS_START *)
|
||||||
|
open OASISDynRun;;
|
||||||
|
open OASISTypes;;
|
||||||
|
(* OASIS_STOP *)
|
||||||
|
|
||||||
|
let () = setup ()
|
149
src/ppx_let.ml
Normal file
149
src/ppx_let.ml
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
open! StdLabels
|
||||||
|
open Ppx_core.Std
|
||||||
|
open Parsetree
|
||||||
|
open Ast_builder.Default
|
||||||
|
|
||||||
|
module List = struct
|
||||||
|
include List
|
||||||
|
|
||||||
|
let reduce_exn l ~f =
|
||||||
|
match l with
|
||||||
|
| [] -> invalid_arg "List.reduce_exn"
|
||||||
|
| hd :: tl -> fold_left tl ~init:hd ~f
|
||||||
|
end
|
||||||
|
|
||||||
|
module Extension_name = struct
|
||||||
|
type t =
|
||||||
|
| Bind
|
||||||
|
| Bind_open
|
||||||
|
| Map
|
||||||
|
| Map_open
|
||||||
|
|
||||||
|
let operator_name = function
|
||||||
|
| Bind | Bind_open -> "bind"
|
||||||
|
| Map | Map_open -> "map"
|
||||||
|
|
||||||
|
let to_string = function
|
||||||
|
| Bind -> "bind"
|
||||||
|
| Bind_open -> "bind_open"
|
||||||
|
| Map -> "map"
|
||||||
|
| Map_open -> "map_open"
|
||||||
|
end
|
||||||
|
|
||||||
|
let let_syntax = "Let_syntax"
|
||||||
|
|
||||||
|
let open_on_rhs ~loc = Located.mk ~loc (Longident.Ldot (Lident let_syntax, "Open_on_rhs" ))
|
||||||
|
let open_in_body ~loc = Located.mk ~loc (Longident.Ldot (Lident let_syntax, "Open_in_body"))
|
||||||
|
|
||||||
|
let eoperator ~loc func =
|
||||||
|
let lid : Longident.t = Ldot (Longident.Lident let_syntax, func) in
|
||||||
|
pexp_ident ~loc (Located.mk ~loc lid)
|
||||||
|
;;
|
||||||
|
|
||||||
|
let expand_with_tmp_vars ~loc bindings expr ~f =
|
||||||
|
match bindings with
|
||||||
|
| [_] -> f ~loc bindings expr
|
||||||
|
| _ ->
|
||||||
|
let tmp_vars = List.map bindings ~f:(fun _ -> gen_symbol ~prefix:"__let_syntax" ()) in
|
||||||
|
let s_rhs_tmp_var (* s/rhs/tmp_var *) =
|
||||||
|
List.map2 bindings tmp_vars ~f:(fun vb var ->
|
||||||
|
{ vb with pvb_expr = evar ~loc:vb.pvb_expr.pexp_loc var })
|
||||||
|
in
|
||||||
|
let s_lhs_tmp_var (* s/lhs/tmp_var *) =
|
||||||
|
List.map2 bindings tmp_vars ~f:(fun vb var ->
|
||||||
|
{ vb with pvb_pat = pvar ~loc:vb.pvb_pat.ppat_loc var })
|
||||||
|
in
|
||||||
|
pexp_let ~loc Nonrecursive s_lhs_tmp_var (f ~loc s_rhs_tmp_var expr)
|
||||||
|
;;
|
||||||
|
|
||||||
|
let bind_apply ~loc extension_name ~arg ~fn =
|
||||||
|
let fn_label =
|
||||||
|
match (extension_name : Extension_name.t) with
|
||||||
|
| Bind | Bind_open -> ""
|
||||||
|
| Map | Map_open -> "f"
|
||||||
|
in
|
||||||
|
pexp_apply ~loc
|
||||||
|
(eoperator ~loc (Extension_name.operator_name extension_name))
|
||||||
|
[("", arg); (fn_label, fn)]
|
||||||
|
;;
|
||||||
|
|
||||||
|
let maybe_open extension_name ~loc ~to_open:module_to_open expr =
|
||||||
|
match (extension_name : Extension_name.t) with
|
||||||
|
| Bind | Map -> expr
|
||||||
|
| Bind_open | Map_open -> pexp_open ~loc Override (module_to_open ~loc) expr
|
||||||
|
;;
|
||||||
|
|
||||||
|
let expand_let extension_name ~loc bindings body =
|
||||||
|
(* Build expression [both E1 (both E2 (both ...))] *)
|
||||||
|
let nested_boths =
|
||||||
|
let rev_boths = List.rev_map bindings ~f:(fun vb -> vb.pvb_expr) in
|
||||||
|
List.reduce_exn rev_boths ~f:(fun acc e ->
|
||||||
|
let loc = e.pexp_loc in
|
||||||
|
eapply ~loc (eoperator ~loc "both") [e; acc])
|
||||||
|
in
|
||||||
|
(* Build pattern [(P1, (P2, ...))] *)
|
||||||
|
let nested_patterns =
|
||||||
|
let rev_patts = List.rev_map bindings ~f:(fun vb -> vb.pvb_pat) in
|
||||||
|
List.reduce_exn rev_patts ~f:(fun acc p ->
|
||||||
|
let loc = p.ppat_loc in
|
||||||
|
ppat_tuple ~loc [p; acc])
|
||||||
|
in
|
||||||
|
bind_apply ~loc extension_name ~arg:nested_boths
|
||||||
|
~fn:(pexp_fun ~loc "" None nested_patterns
|
||||||
|
(maybe_open extension_name ~loc ~to_open:open_in_body body))
|
||||||
|
;;
|
||||||
|
|
||||||
|
let expand_match extension_name ~loc expr cases =
|
||||||
|
let cases =
|
||||||
|
List.map cases ~f:(fun case ->
|
||||||
|
{ case with
|
||||||
|
pc_rhs = maybe_open extension_name ~loc ~to_open:open_in_body case.pc_rhs;
|
||||||
|
})
|
||||||
|
in
|
||||||
|
bind_apply ~loc extension_name
|
||||||
|
~arg:(maybe_open extension_name ~loc ~to_open:open_on_rhs expr)
|
||||||
|
~fn:(pexp_function ~loc cases)
|
||||||
|
;;
|
||||||
|
|
||||||
|
let expand ~loc:_ ~path:_ extension_name expr =
|
||||||
|
let loc = expr.pexp_loc in
|
||||||
|
let expansion =
|
||||||
|
match expr.pexp_desc with
|
||||||
|
| Pexp_let (Nonrecursive, bindings, expr) ->
|
||||||
|
let bindings =
|
||||||
|
List.map bindings ~f:(fun vb ->
|
||||||
|
{ vb with
|
||||||
|
pvb_expr = maybe_open extension_name ~loc ~to_open:open_on_rhs vb.pvb_expr;
|
||||||
|
})
|
||||||
|
in
|
||||||
|
expand_with_tmp_vars ~loc bindings expr ~f:(expand_let extension_name)
|
||||||
|
| Pexp_let (Recursive, _, _) ->
|
||||||
|
Location.raise_errorf ~loc "'let%%%s' may not be recursive"
|
||||||
|
(Extension_name.to_string extension_name)
|
||||||
|
| Pexp_match (expr, cases) ->
|
||||||
|
expand_match extension_name ~loc expr cases
|
||||||
|
| _ ->
|
||||||
|
Location.raise_errorf ~loc
|
||||||
|
"'%%%s' can only be used with 'let' and 'match'"
|
||||||
|
(Extension_name.to_string extension_name)
|
||||||
|
in
|
||||||
|
{ expansion with pexp_attributes = expr.pexp_attributes @ expansion.pexp_attributes }
|
||||||
|
;;
|
||||||
|
|
||||||
|
let ext extension_name =
|
||||||
|
Extension.V2.declare
|
||||||
|
(Extension_name.to_string extension_name)
|
||||||
|
Extension.Context.expression
|
||||||
|
Ast_pattern.(single_expr_payload __)
|
||||||
|
(expand extension_name)
|
||||||
|
;;
|
||||||
|
|
||||||
|
let () =
|
||||||
|
Ppx_driver.register_transformation "let"
|
||||||
|
~extensions:[
|
||||||
|
ext Bind;
|
||||||
|
ext Bind_open;
|
||||||
|
ext Map;
|
||||||
|
ext Map_open;
|
||||||
|
]
|
||||||
|
;;
|
1
src/ppx_let.mli
Normal file
1
src/ppx_let.mli
Normal file
@ -0,0 +1 @@
|
|||||||
|
(* This signature is deliberately empty. *)
|
229
test/test.ml
Normal file
229
test/test.ml
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
module Monad_example = struct
|
||||||
|
|
||||||
|
module X : sig
|
||||||
|
type 'a t
|
||||||
|
module Let_syntax : sig
|
||||||
|
val return : 'a -> 'a t
|
||||||
|
val bind : 'a t -> ('a -> 'b t) -> 'b t
|
||||||
|
val map : 'a t -> f:('a -> 'b) -> 'b t
|
||||||
|
val both : 'a t -> 'b t -> ('a * 'b) t
|
||||||
|
module Open_on_rhs : sig val return : 'a -> 'a t end
|
||||||
|
module Open_in_body : sig val return : 'a -> 'a t end
|
||||||
|
end
|
||||||
|
end = struct
|
||||||
|
type 'a t = 'a
|
||||||
|
let return x = x
|
||||||
|
let bind x f = f x
|
||||||
|
let map x ~f = f x
|
||||||
|
let both x y = (x, y)
|
||||||
|
module Let_syntax = struct
|
||||||
|
let return = return
|
||||||
|
let bind = bind
|
||||||
|
let map = map
|
||||||
|
let both = both
|
||||||
|
module Open_on_rhs = struct let return = return end
|
||||||
|
module Open_in_body = struct let return = return end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module Let_syntax = X.Let_syntax
|
||||||
|
|
||||||
|
let _mf a : _ X.t =
|
||||||
|
let%bind_open x = a in
|
||||||
|
return (x + 1)
|
||||||
|
|
||||||
|
let _mf' a b c : _ X.t =
|
||||||
|
let%bind_open x = a and y = b and (u, v) = c in
|
||||||
|
return (x + y + (u * v))
|
||||||
|
|
||||||
|
let _mg a : _ X.t =
|
||||||
|
let%map x = a in
|
||||||
|
x + 1
|
||||||
|
|
||||||
|
let _mg' a b c : _ X.t =
|
||||||
|
let%map x = a and y = b and (u, v) = c in
|
||||||
|
x + y + (u * v)
|
||||||
|
|
||||||
|
let _mh a : _ X.t =
|
||||||
|
match%bind_open a with
|
||||||
|
| 0 -> return true
|
||||||
|
| _ -> return false
|
||||||
|
|
||||||
|
let _mi a : _ X.t =
|
||||||
|
match%map a with
|
||||||
|
| 0 -> true
|
||||||
|
| _ -> false
|
||||||
|
end
|
||||||
|
|
||||||
|
module Applicative_example = struct
|
||||||
|
|
||||||
|
module X : sig
|
||||||
|
type 'a t
|
||||||
|
module Let_syntax : sig
|
||||||
|
val return : 'a -> 'a t
|
||||||
|
val map : 'a t -> f:('a -> 'b) -> 'b t
|
||||||
|
val both : 'a t -> 'b t -> ('a * 'b) t
|
||||||
|
module Open_on_rhs : sig
|
||||||
|
val flag : int t
|
||||||
|
val anon : int t
|
||||||
|
end
|
||||||
|
module Open_in_body : sig end
|
||||||
|
end
|
||||||
|
end = struct
|
||||||
|
type 'a t = 'a
|
||||||
|
let return x = x
|
||||||
|
let map x ~f = f x
|
||||||
|
let both x y = (x, y)
|
||||||
|
module Let_syntax = struct
|
||||||
|
let return = return
|
||||||
|
let map = map
|
||||||
|
let both = both
|
||||||
|
module Open_on_rhs = struct
|
||||||
|
let flag = 66
|
||||||
|
let anon = 77
|
||||||
|
end
|
||||||
|
module Open_in_body = struct end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module Let_syntax = X.Let_syntax
|
||||||
|
|
||||||
|
(* {[
|
||||||
|
let _af a : _ X.t =
|
||||||
|
let%bind x = a in (* "Error: Unbound value Let_syntax.bind" *)
|
||||||
|
return (x + 1)
|
||||||
|
]} *)
|
||||||
|
|
||||||
|
(* {[
|
||||||
|
let _af' a b c : _ X.t =
|
||||||
|
let%bind x = a and y = b and (u, v) = c in (* "Error: Unbound value Let_syntax.bind" *)
|
||||||
|
return (x + y + (u * v))
|
||||||
|
]} *)
|
||||||
|
|
||||||
|
let _ag a : _ X.t =
|
||||||
|
let%map x = a in
|
||||||
|
x + 1
|
||||||
|
|
||||||
|
let _ag' a b c : _ X.t =
|
||||||
|
let%map x = a and y = b and (u, v) = c in
|
||||||
|
x + y + (u * v)
|
||||||
|
|
||||||
|
(* {[
|
||||||
|
let _ah a : _ X.t =
|
||||||
|
match%bind a with (* "Error: Unbound value Let_syntax.bind" *)
|
||||||
|
| 0 -> return true
|
||||||
|
| _ -> return false
|
||||||
|
]} *)
|
||||||
|
|
||||||
|
let _ai a : _ X.t =
|
||||||
|
match%map a with
|
||||||
|
| 0 -> true
|
||||||
|
| _ -> false
|
||||||
|
end
|
||||||
|
|
||||||
|
module Async_command_override_example = struct
|
||||||
|
|
||||||
|
module Deferred : sig
|
||||||
|
type 'a t
|
||||||
|
val return : 'a -> 'a t
|
||||||
|
module Let_syntax : sig
|
||||||
|
type 'a t
|
||||||
|
val return : 'a -> 'a t
|
||||||
|
val map : 'a t -> f:('a -> 'b) -> 'b t
|
||||||
|
val both : 'a t -> 'b t -> ('a * 'b) t
|
||||||
|
module Open_on_rhs : sig val return : 'a -> 'a t end
|
||||||
|
module Open_in_body : sig val return : 'a -> 'a t end
|
||||||
|
end with type 'a t := 'a t
|
||||||
|
end = struct
|
||||||
|
type 'a t = 'a
|
||||||
|
let return x = x
|
||||||
|
module Let_syntax = struct
|
||||||
|
let return = return
|
||||||
|
let map x ~f = f x
|
||||||
|
let both x y = (x, y)
|
||||||
|
module Open_on_rhs = struct let return = return end
|
||||||
|
module Open_in_body = struct let return = return end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module Command : sig
|
||||||
|
module Param : sig
|
||||||
|
type 'a t
|
||||||
|
val return : 'a -> 'a t
|
||||||
|
val flag : 'a -> int t
|
||||||
|
val anon : 'a -> int t
|
||||||
|
end
|
||||||
|
module Let_syntax : sig
|
||||||
|
type 'a t
|
||||||
|
val return : 'a -> 'a t
|
||||||
|
val map : 'a t -> f:('a -> 'b) -> 'b t
|
||||||
|
val both : 'a t -> 'b t -> ('a * 'b) t
|
||||||
|
module Open_on_rhs = Param
|
||||||
|
module Open_in_body : sig end
|
||||||
|
end with type 'a t := 'a Param.t
|
||||||
|
end = struct
|
||||||
|
module Param = struct
|
||||||
|
type 'a t = 'a
|
||||||
|
let return x = x
|
||||||
|
let map x ~f = f x
|
||||||
|
let both x y = (x, y)
|
||||||
|
let flag _ = 66
|
||||||
|
let anon _ = 77
|
||||||
|
end
|
||||||
|
module Let_syntax = struct
|
||||||
|
include Param
|
||||||
|
module Open_on_rhs = Param
|
||||||
|
module Open_in_body = struct end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module Command_override = struct
|
||||||
|
module Param = struct
|
||||||
|
include Command.Param
|
||||||
|
let special_flag = flag 88
|
||||||
|
end
|
||||||
|
module Let_syntax = struct
|
||||||
|
include (Command.Let_syntax : module type of Command.Let_syntax
|
||||||
|
with module Open_on_rhs := Command.Let_syntax.Open_on_rhs
|
||||||
|
and module Open_in_body := Command.Let_syntax.Open_in_body)
|
||||||
|
|
||||||
|
module Open_on_rhs = Param
|
||||||
|
module Open_in_body = struct
|
||||||
|
module Let_syntax = Deferred.Let_syntax
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let _1 : int Command.Param.t =
|
||||||
|
let module Let_syntax = Command.Let_syntax in
|
||||||
|
[%map_open
|
||||||
|
let x = flag "foo"
|
||||||
|
and y = anon "bar"
|
||||||
|
in
|
||||||
|
x + y
|
||||||
|
]
|
||||||
|
;;
|
||||||
|
|
||||||
|
let _1 : (unit -> int Deferred.t) Command_override.Param.t =
|
||||||
|
let module Let_syntax = Command_override.Let_syntax in
|
||||||
|
[%map_open
|
||||||
|
let x = flag "foo"
|
||||||
|
and y = anon "bar"
|
||||||
|
and z = special_flag
|
||||||
|
in
|
||||||
|
(fun () ->
|
||||||
|
let%map () = Deferred.return () in
|
||||||
|
x + y + z)
|
||||||
|
]
|
||||||
|
;;
|
||||||
|
|
||||||
|
let _1 : (unit -> unit Deferred.t) Command.Param.t =
|
||||||
|
let module Let_syntax = Command_override.Let_syntax in
|
||||||
|
[%map_open
|
||||||
|
let () = return () in
|
||||||
|
fun () ->
|
||||||
|
let%map () = Deferred.return () in
|
||||||
|
()
|
||||||
|
]
|
||||||
|
;;
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user