├── .github └── workflows │ └── web.yaml ├── .gitignore ├── LICENSE ├── cabal.project ├── flake.lock ├── flake.nix ├── index.html ├── main.js ├── module.html ├── shake ├── HTML │ ├── Backend.hs │ └── Base.hs ├── LICENSE.agda ├── Main.hs └── cubical-experiments-shake.cabal ├── src-1lab ├── AdjunctionCommaIso.agda ├── Applicative.agda ├── CoherentlyConstant.agda ├── EasyParametricity.lagda.md ├── ErasureOpen.lagda.md ├── FirstGroupCohomology.agda ├── Goat.agda ├── Hats.agda ├── Madeleine.agda ├── MonoidalFibres.agda ├── Mystery.agda ├── Möbius.agda ├── ObjectClassifier.agda ├── PointwiseMonoidal.agda ├── PostcomposeNotFull.agda ├── PresheafExponential.agda ├── Probability.agda ├── Skeletons.agda ├── SplitMonoSet.agda ├── SyntheticCategoricalDuality.lagda.md ├── TangentBundlesOfSpheres.lagda.md ├── Untruncate.agda ├── YonedaColimit.agda └── src-1lab.agda-lib ├── src ├── DeMorKan.agda ├── Erasure.agda ├── NaiveFunext.agda ├── NatChurchMonoid.agda ├── Shapes.agda ├── Torus.agda └── src.agda-lib └── style.css /.github/workflows/web.yaml: -------------------------------------------------------------------------------- 1 | name: web 2 | on: [push, pull_request, workflow_dispatch] 3 | jobs: 4 | build: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v4 8 | - uses: cachix/install-nix-action@v27 9 | with: 10 | extra_nix_config: | 11 | access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} 12 | extra-substituters = https://nix.monade.li 13 | extra-trusted-public-keys = nix.monade.li:2Zgy59ai/edDBizXByHMqiGgaHlE04G6Nzuhx1RPFgo= 14 | - uses: cachix/cachix-action@v15 15 | with: 16 | name: ncfavier 17 | authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} 18 | extraPullNames: 1lab 19 | - name: Build 20 | run: | 21 | web=$(nix -L build --print-out-paths) 22 | cp -rL --no-preserve=mode,ownership,timestamps "$web" pages 23 | - uses: actions/upload-pages-artifact@v3 24 | with: 25 | path: pages 26 | retention-days: 1 27 | deploy: 28 | if: github.ref_name == 'main' 29 | needs: build 30 | permissions: 31 | pages: write 32 | id-token: write 33 | environment: 34 | name: github-pages 35 | url: ${{ steps.deployment.outputs.page_url }} 36 | runs-on: ubuntu-latest 37 | steps: 38 | - id: deployment 39 | uses: actions/deploy-pages@v4 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | result 2 | result-* 3 | *.agdai 4 | MAlonzo/** 5 | .shake 6 | dist-newstyle 7 | _build 8 | Everything*.agda 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /cabal.project: -------------------------------------------------------------------------------- 1 | packages: shake 2 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "nixpkgs": { 4 | "locked": { 5 | "lastModified": 1745872597, 6 | "narHash": "sha256-o7ROtc5q4ISWsF+nuENjeITzaZsaXO7OiNOLg9+h88k=", 7 | "owner": "ncfavier", 8 | "repo": "nixpkgs", 9 | "rev": "029495dc0dcfb45f51db8ccb4a9ed63eed4a94f4", 10 | "type": "github" 11 | }, 12 | "original": { 13 | "owner": "ncfavier", 14 | "ref": "agda-bump", 15 | "repo": "nixpkgs", 16 | "type": "github" 17 | } 18 | }, 19 | "root": { 20 | "inputs": { 21 | "nixpkgs": "nixpkgs", 22 | "the1lab": "the1lab" 23 | } 24 | }, 25 | "the1lab": { 26 | "flake": false, 27 | "locked": { 28 | "lastModified": 1748348495, 29 | "narHash": "sha256-SGeo5WjW6qCMb0YFWdelXEK/6h0tLPwgGJglYGHxa6E=", 30 | "owner": "the1lab", 31 | "repo": "1lab", 32 | "rev": "aafcd46dd4d4cff3bfff260a2decb067d61531ad", 33 | "type": "github" 34 | }, 35 | "original": { 36 | "owner": "the1lab", 37 | "repo": "1lab", 38 | "type": "github" 39 | } 40 | } 41 | }, 42 | "root": "root", 43 | "version": 7 44 | } 45 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs = { 3 | nixpkgs.url = "github:ncfavier/nixpkgs/agda-bump"; 4 | the1lab = { 5 | url = "github:the1lab/1lab"; 6 | flake = false; 7 | }; 8 | }; 9 | 10 | outputs = inputs@{ self, nixpkgs, ... }: let 11 | system = "x86_64-linux"; 12 | pkgs = import nixpkgs { 13 | inherit system; 14 | overlays = [ (self: super: { 15 | agdaPackages = super.agdaPackages.overrideScope (aself: asuper: { 16 | _1lab = asuper._1lab.overrideAttrs { 17 | version = "unstable-${inputs.the1lab.shortRev}"; 18 | src = inputs.the1lab; 19 | }; 20 | }); 21 | }) ]; 22 | }; 23 | 24 | agdaLibs = libs: [ 25 | libs.standard-library 26 | libs.cubical 27 | libs._1lab 28 | ]; 29 | agda = pkgs.agda.withPackages agdaLibs; 30 | AGDA_LIBRARIES_FILE = pkgs.agdaPackages.mkLibraryFile agdaLibs; 31 | Agda_datadir = "${pkgs.haskellPackages.Agda.data}/share/agda"; 32 | 33 | shakefile = pkgs.haskellPackages.callCabal2nix "cubical-experiments-shake" ./shake {}; 34 | in { 35 | devShells.${system} = { 36 | default = self.packages.${system}.default.overrideAttrs (old: { 37 | nativeBuildInputs = old.nativeBuildInputs or [] ++ [ agda ]; 38 | }); 39 | 40 | shakefile = pkgs.haskellPackages.shellFor { 41 | packages = _: [ shakefile ]; 42 | inherit AGDA_LIBRARIES_FILE Agda_datadir; 43 | }; 44 | }; 45 | 46 | packages.${system} = { 47 | default = pkgs.stdenv.mkDerivation { 48 | name = "cubical-experiments"; 49 | src = self; 50 | nativeBuildInputs = [ shakefile ]; 51 | inherit AGDA_LIBRARIES_FILE Agda_datadir; 52 | LC_ALL = "C.UTF-8"; 53 | buildPhase = '' 54 | cubical-experiments-shake 55 | mv _build/site "$out" 56 | ''; 57 | }; 58 | 59 | inherit shakefile; 60 | }; 61 | }; 62 | } 63 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | cubical-experiments 8 | 9 | 10 | 11 | 12 |

cubical-experiments

13 |
14 | @contents@
15 | 16 | 17 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | function scrollToHash() { 2 | if (window.location.hash === '') return; 3 | 4 | const id = decodeURI(window.location.hash.slice(1)); 5 | 6 | // #id doesn't work with numerical IDs 7 | const elem = document.querySelector(`[id="${id}"]`); 8 | if (!elem) return; 9 | 10 | // If the element is in a
tag, open it and scroll to it. 11 | const details = elem.closest('details'); 12 | if (details) { 13 | details.setAttribute("open", ""); 14 | elem.scrollIntoView(); 15 | } 16 | } 17 | 18 | window.addEventListener("DOMContentLoaded", scrollToHash); 19 | window.addEventListener("hashchange", scrollToHash); 20 | -------------------------------------------------------------------------------- /module.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | @moduleName@ 8 | 9 | 10 | 11 | 12 | 13 | 14 |

15 | index ∙ 16 | source 17 |

18 | @contents@ 19 | 20 | 21 | -------------------------------------------------------------------------------- /shake/HTML/Backend.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS_GHC -Wunused-imports #-} 2 | 3 | -- | Backend for generating highlighted, hyperlinked HTML from Agda sources. 4 | 5 | module HTML.Backend 6 | ( htmlBackend 7 | , htmlBackend' 8 | , HtmlFlags(..) 9 | , initialHtmlFlags 10 | ) where 11 | 12 | import HTML.Base 13 | 14 | import Prelude hiding ((!!), concatMap) 15 | 16 | import Control.DeepSeq 17 | import Control.Monad.Trans ( MonadIO ) 18 | import Control.Monad.Except ( MonadError(throwError) ) 19 | 20 | import Data.Maybe 21 | import qualified Data.Map as Map 22 | import Data.Map (Map) 23 | 24 | import GHC.Generics (Generic) 25 | 26 | import Agda.Interaction.Options 27 | ( ArgDescr(ReqArg, NoArg) 28 | , OptDescr(..) 29 | ) 30 | import Agda.Compiler.Backend 31 | import Agda.Compiler.Common (curIF) 32 | import Agda.Interaction.Library.Base (_libName, LibName) 33 | import Agda.Utils.FileName 34 | 35 | -- | Options for HTML generation 36 | 37 | data HtmlFlags = HtmlFlags 38 | { htmlFlagEnabled :: Bool 39 | , htmlFlagDir :: FilePath 40 | , htmlFlagHighlight :: HtmlHighlight 41 | , htmlFlagHighlightOccurrences :: Bool 42 | , htmlFlagCssFile :: Maybe FilePath 43 | , htmlFlagLibToURL :: LibName -> Maybe String 44 | } deriving (Generic) 45 | 46 | instance NFData HtmlFlags 47 | 48 | data HtmlCompileEnv = HtmlCompileEnv 49 | { htmlCompileEnvOpts :: HtmlOptions 50 | , htmlModuleToURL :: ModuleToURL 51 | } 52 | 53 | data HtmlModuleEnv = HtmlModuleEnv 54 | { htmlModEnvCompileEnv :: HtmlCompileEnv 55 | , htmlModEnvName :: TopLevelModuleName 56 | } 57 | 58 | data HtmlModule = HtmlModule 59 | data HtmlDef = HtmlDef 60 | 61 | htmlBackend :: Backend 62 | htmlBackend = Backend htmlBackend' 63 | 64 | htmlBackend' :: Backend' HtmlFlags HtmlCompileEnv HtmlModuleEnv HtmlModule HtmlDef 65 | htmlBackend' = Backend' 66 | { backendName = "HTML" 67 | , backendVersion = Nothing 68 | , options = initialHtmlFlags 69 | , commandLineFlags = htmlFlags 70 | , isEnabled = htmlFlagEnabled 71 | , preCompile = preCompileHtml 72 | , preModule = preModuleHtml 73 | , compileDef = compileDefHtml 74 | , postModule = postModuleHtml 75 | , postCompile = postCompileHtml 76 | -- --only-scope-checking works, but with the caveat that cross-module links 77 | -- will not have their definition site populated. 78 | , scopeCheckingSuffices = True 79 | , mayEraseType = const $ return False 80 | , backendInteractTop = Nothing 81 | , backendInteractHole = Nothing 82 | } 83 | 84 | initialHtmlFlags :: HtmlFlags 85 | initialHtmlFlags = HtmlFlags 86 | { htmlFlagEnabled = False 87 | , htmlFlagDir = defaultHTMLDir 88 | , htmlFlagHighlight = HighlightAll 89 | -- Don't enable by default because it causes potential 90 | -- performance problems 91 | , htmlFlagHighlightOccurrences = False 92 | , htmlFlagCssFile = Nothing 93 | , htmlFlagLibToURL = const Nothing 94 | } 95 | 96 | htmlOptsOfFlags :: HtmlFlags -> HtmlOptions 97 | htmlOptsOfFlags flags = HtmlOptions 98 | { htmlOptDir = htmlFlagDir flags 99 | , htmlOptHighlight = htmlFlagHighlight flags 100 | , htmlOptHighlightOccurrences = htmlFlagHighlightOccurrences flags 101 | , htmlOptCssFile = htmlFlagCssFile flags 102 | } 103 | 104 | -- | The default output directory for HTML. 105 | 106 | defaultHTMLDir :: FilePath 107 | defaultHTMLDir = "html" 108 | 109 | htmlFlags :: [OptDescr (Flag HtmlFlags)] 110 | htmlFlags = 111 | [ Option [] ["html"] (NoArg htmlFlag) 112 | "generate HTML files with highlighted source code" 113 | , Option [] ["html-dir"] (ReqArg htmlDirFlag "DIR") 114 | ("directory in which HTML files are placed (default: " ++ 115 | defaultHTMLDir ++ ")") 116 | , Option [] ["highlight-occurrences"] (NoArg highlightOccurrencesFlag) 117 | ("highlight all occurrences of hovered symbol in generated " ++ 118 | "HTML files") 119 | , Option [] ["css"] (ReqArg cssFlag "URL") 120 | "the CSS file used by the HTML files (can be relative)" 121 | , Option [] ["html-highlight"] (ReqArg htmlHighlightFlag "[code,all,auto]") 122 | ("whether to highlight only the code parts (code) or " ++ 123 | "the file as a whole (all) or " ++ 124 | "decide by source file type (auto)") 125 | ] 126 | 127 | htmlFlag :: Flag HtmlFlags 128 | htmlFlag o = return $ o { htmlFlagEnabled = True } 129 | 130 | htmlDirFlag :: FilePath -> Flag HtmlFlags 131 | htmlDirFlag d o = return $ o { htmlFlagDir = d } 132 | 133 | cssFlag :: FilePath -> Flag HtmlFlags 134 | cssFlag f o = return $ o { htmlFlagCssFile = Just f } 135 | 136 | highlightOccurrencesFlag :: Flag HtmlFlags 137 | highlightOccurrencesFlag o = return $ o { htmlFlagHighlightOccurrences = True } 138 | 139 | parseHtmlHighlightFlag :: MonadError String m => String -> m HtmlHighlight 140 | parseHtmlHighlightFlag "code" = return HighlightCode 141 | parseHtmlHighlightFlag "all" = return HighlightAll 142 | parseHtmlHighlightFlag "auto" = return HighlightAuto 143 | parseHtmlHighlightFlag opt = throwError $ concat ["Invalid option <", opt, ">, expected , or "] 144 | 145 | htmlHighlightFlag :: String -> Flag HtmlFlags 146 | htmlHighlightFlag opt o = do 147 | flag <- parseHtmlHighlightFlag opt 148 | return $ o { htmlFlagHighlight = flag } 149 | 150 | runLogHtmlWithMonadDebug :: MonadDebug m => LogHtmlT m a -> m a 151 | runLogHtmlWithMonadDebug = runLogHtmlWith $ reportS "html" 1 152 | 153 | preCompileHtml 154 | :: HtmlFlags 155 | -> TCM HtmlCompileEnv 156 | preCompileHtml flags = do 157 | moduleToSourceId <- useTC stModuleToSourceId 158 | modulesToURL <- Map.traverseWithKey moduleToURL moduleToSourceId 159 | runLogHtmlWithMonadDebug $ do 160 | logHtml $ unlines 161 | [ "Warning: HTML is currently generated for ALL files which can be" 162 | , "reached from the given module, including library files." 163 | ] 164 | let opts = htmlOptsOfFlags flags 165 | prepareCommonDestinationAssets opts 166 | return $ HtmlCompileEnv opts modulesToURL 167 | where 168 | moduleToURL :: TopLevelModuleName -> SourceFile -> TCM String 169 | moduleToURL m sf = do 170 | p <- srcFilePath sf 171 | agdaLibs <- getAgdaLibFiles p m 172 | case mapMaybe (htmlFlagLibToURL flags . _libName) agdaLibs of 173 | u:_ -> pure u 174 | _ -> fail ("Failed to find link target for file " <> filePath p) 175 | 176 | preModuleHtml 177 | :: Applicative m 178 | => HtmlCompileEnv 179 | -> IsMain 180 | -> TopLevelModuleName 181 | -> Maybe FilePath 182 | -> m (Recompile HtmlModuleEnv HtmlModule) 183 | preModuleHtml cenv _isMain modName _ifacePath = pure $ Recompile (HtmlModuleEnv cenv modName) 184 | 185 | compileDefHtml 186 | :: Applicative m 187 | => HtmlCompileEnv 188 | -> HtmlModuleEnv 189 | -> IsMain 190 | -> Definition 191 | -> m HtmlDef 192 | compileDefHtml _env _menv _isMain _def = pure HtmlDef 193 | 194 | postModuleHtml 195 | :: (MonadIO m, MonadDebug m, ReadTCState m) 196 | => HtmlCompileEnv 197 | -> HtmlModuleEnv 198 | -> IsMain 199 | -> TopLevelModuleName 200 | -> [HtmlDef] 201 | -> m HtmlModule 202 | postModuleHtml env menv _isMain _modName _defs = do 203 | let generatePage = defaultPageGen (htmlModuleToURL env) . htmlCompileEnvOpts . htmlModEnvCompileEnv $ menv 204 | htmlSrc <- srcFileOfInterface (htmlModEnvName menv) <$> curIF 205 | runLogHtmlWithMonadDebug $ generatePage htmlSrc 206 | return HtmlModule 207 | 208 | postCompileHtml 209 | :: Applicative m 210 | => HtmlCompileEnv 211 | -> IsMain 212 | -> Map TopLevelModuleName HtmlModule 213 | -> m () 214 | postCompileHtml _cenv _isMain _modulesByName = pure () 215 | -------------------------------------------------------------------------------- /shake/HTML/Base.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS_GHC -Wunused-imports #-} 2 | 3 | -- | Function for generating highlighted, hyperlinked HTML from Agda 4 | -- sources. 5 | 6 | module HTML.Base 7 | ( HtmlOptions(..) 8 | , HtmlHighlight(..) 9 | , prepareCommonDestinationAssets 10 | , srcFileOfInterface 11 | , defaultPageGen 12 | , MonadLogHtml(logHtml) 13 | , LogHtmlT 14 | , runLogHtmlWith 15 | , ModuleToURL 16 | ) where 17 | 18 | import Prelude hiding ((!!), concatMap) 19 | 20 | import Control.DeepSeq 21 | import Control.Monad 22 | import Control.Monad.Trans ( MonadIO(..), lift ) 23 | import Control.Monad.Trans.Reader ( ReaderT(runReaderT), ask ) 24 | 25 | import Data.Foldable (toList, concatMap) 26 | import Data.Maybe 27 | import qualified Data.IntMap as IntMap 28 | import qualified Data.Map as Map 29 | import Data.Map (Map) 30 | import Data.List.Split (splitWhen) 31 | import Data.Text.Lazy (Text) 32 | import qualified Data.Text.Lazy as T 33 | 34 | import GHC.Generics (Generic) 35 | 36 | import qualified Network.URI.Encode 37 | 38 | import System.FilePath 39 | import System.Directory 40 | 41 | import Text.Blaze.Html5 42 | ( preEscapedToHtml 43 | , toHtml 44 | , stringValue 45 | , Html 46 | , (!) 47 | , Attribute 48 | ) 49 | import qualified Text.Blaze.Html5 as Html5 50 | import qualified Text.Blaze.Html5.Attributes as Attr 51 | import Text.Blaze.Html.Renderer.Text ( renderHtml ) 52 | -- The imported operator (!) attaches an Attribute to an Html value 53 | -- The defined operator (!!) attaches a list of such Attributes 54 | 55 | import Agda.Interaction.Highlighting.Precise hiding (toList) 56 | 57 | import Agda.Syntax.Common 58 | import Agda.Syntax.TopLevelModuleName 59 | 60 | import qualified Agda.TypeChecking.Monad as TCM 61 | ( Interface(..) 62 | ) 63 | 64 | import Agda.Utils.Function 65 | import Agda.Utils.List1 (String1, pattern (:|)) 66 | import qualified Agda.Utils.List1 as List1 67 | import qualified Agda.Utils.IO.UTF8 as UTF8 68 | import Agda.Syntax.Common.Pretty 69 | 70 | import Agda.Utils.Impossible 71 | import Agda.Utils.String (rtrim) 72 | import Agda.Main (printAgdaDataDir) 73 | 74 | import System.IO.Silently 75 | 76 | type ModuleToURL = Map TopLevelModuleName String 77 | 78 | getDataFileName :: FilePath -> IO FilePath 79 | getDataFileName name = do 80 | dir <- capture_ printAgdaDataDir -- ... 81 | return (rtrim dir name) 82 | 83 | -- | The Agda data directory containing the files for the HTML backend. 84 | 85 | htmlDataDir :: FilePath 86 | htmlDataDir = "html" 87 | 88 | -- | The name of the default CSS file. 89 | 90 | defaultCSSFile :: FilePath 91 | defaultCSSFile = "Agda.css" 92 | 93 | -- | The name of the occurrence-highlighting JS file. 94 | 95 | occurrenceHighlightJsFile :: FilePath 96 | occurrenceHighlightJsFile = "highlight-hover.js" 97 | 98 | -- | The directive inserted before the rendered code blocks 99 | 100 | rstDelimiter :: String 101 | rstDelimiter = ".. raw:: html\n" 102 | 103 | -- | The directive inserted before rendered code blocks in org 104 | 105 | orgDelimiterStart :: String 106 | orgDelimiterStart = "#+BEGIN_EXPORT html\n
\n"
107 | 
108 | -- | The directive inserted after rendered code blocks in org
109 | 
110 | orgDelimiterEnd :: String
111 | orgDelimiterEnd = "
\n#+END_EXPORT\n" 112 | 113 | -- | Determine how to highlight the file 114 | 115 | data HtmlHighlight = HighlightAll | HighlightCode | HighlightAuto 116 | deriving (Show, Eq, Generic) 117 | 118 | instance NFData HtmlHighlight 119 | 120 | highlightOnlyCode :: HtmlHighlight -> FileType -> Bool 121 | highlightOnlyCode HighlightAll _ = False 122 | highlightOnlyCode HighlightCode _ = True 123 | highlightOnlyCode HighlightAuto AgdaFileType = False 124 | highlightOnlyCode HighlightAuto MdFileType = True 125 | highlightOnlyCode HighlightAuto RstFileType = True 126 | highlightOnlyCode HighlightAuto OrgFileType = True 127 | highlightOnlyCode HighlightAuto TypstFileType = True 128 | highlightOnlyCode HighlightAuto TreeFileType = True 129 | highlightOnlyCode HighlightAuto TexFileType = False 130 | 131 | -- | Determine the generated file extension 132 | 133 | highlightedFileExt :: HtmlHighlight -> FileType -> String 134 | highlightedFileExt hh ft 135 | | not $ highlightOnlyCode hh ft = "html" 136 | | otherwise = case ft of 137 | AgdaFileType -> "html" 138 | MdFileType -> "md" 139 | RstFileType -> "rst" 140 | TexFileType -> "tex" 141 | OrgFileType -> "org" 142 | TypstFileType -> "typ" 143 | TreeFileType -> "tree" 144 | 145 | -- | Options for HTML generation 146 | 147 | data HtmlOptions = HtmlOptions 148 | { htmlOptDir :: FilePath 149 | , htmlOptHighlight :: HtmlHighlight 150 | , htmlOptHighlightOccurrences :: Bool 151 | , htmlOptCssFile :: Maybe FilePath 152 | } deriving Eq 153 | 154 | -- | Internal type bundling the information related to a module source file 155 | 156 | data HtmlInputSourceFile = HtmlInputSourceFile 157 | { _srcFileModuleName :: TopLevelModuleName 158 | , _srcFileType :: FileType 159 | -- ^ Source file type 160 | , _srcFileText :: Text 161 | -- ^ Source text 162 | , _srcFileHighlightInfo :: HighlightingInfo 163 | -- ^ Highlighting info 164 | } 165 | 166 | -- | Bundle up the highlighting info for a source file 167 | 168 | srcFileOfInterface :: 169 | TopLevelModuleName -> TCM.Interface -> HtmlInputSourceFile 170 | srcFileOfInterface m i = HtmlInputSourceFile m (TCM.iFileType i) (TCM.iSource i) (TCM.iHighlighting i) 171 | 172 | -- | Logging during HTML generation 173 | 174 | type HtmlLogMessage = String 175 | type HtmlLogAction m = HtmlLogMessage -> m () 176 | 177 | class MonadLogHtml m where 178 | logHtml :: HtmlLogAction m 179 | 180 | type LogHtmlT m = ReaderT (HtmlLogAction m) m 181 | 182 | instance Monad m => MonadLogHtml (LogHtmlT m) where 183 | logHtml message = do 184 | doLog <- ask 185 | lift $ doLog message 186 | 187 | runLogHtmlWith :: Monad m => HtmlLogAction m -> LogHtmlT m a -> m a 188 | runLogHtmlWith = flip runReaderT 189 | 190 | renderSourceFile :: ModuleToURL -> HtmlOptions -> HtmlInputSourceFile -> Text 191 | renderSourceFile moduleToURL opts = renderSourcePage 192 | where 193 | cssFile = fromMaybe defaultCSSFile (htmlOptCssFile opts) 194 | highlightOccur = htmlOptHighlightOccurrences opts 195 | htmlHighlight = htmlOptHighlight opts 196 | renderSourcePage (HtmlInputSourceFile moduleName fileType sourceCode hinfo) = 197 | page cssFile highlightOccur onlyCode moduleName pageContents 198 | where 199 | tokens = tokenStream sourceCode hinfo 200 | onlyCode = highlightOnlyCode htmlHighlight fileType 201 | pageContents = code moduleToURL onlyCode fileType tokens 202 | 203 | defaultPageGen :: (MonadIO m, MonadLogHtml m) => ModuleToURL -> HtmlOptions -> HtmlInputSourceFile -> m () 204 | defaultPageGen moduleToURL opts srcFile@(HtmlInputSourceFile moduleName ft _ _) = do 205 | logHtml $ render $ "Generating HTML for" <+> pretty moduleName <+> ((parens (pretty target)) <> ".") 206 | writeRenderedHtml html target 207 | where 208 | ext = highlightedFileExt (htmlOptHighlight opts) ft 209 | target = (htmlOptDir opts) modToFile moduleName ext 210 | html = renderSourceFile moduleToURL opts srcFile 211 | 212 | prepareCommonDestinationAssets :: MonadIO m => HtmlOptions -> m () 213 | prepareCommonDestinationAssets options = liftIO $ do 214 | -- There is a default directory given by 'defaultHTMLDir' 215 | let htmlDir = htmlOptDir options 216 | createDirectoryIfMissing True htmlDir 217 | 218 | -- If the default CSS file should be used, then it is copied to 219 | -- the output directory. 220 | let cssFile = htmlOptCssFile options 221 | when (isNothing $ cssFile) $ do 222 | defCssFile <- getDataFileName $ 223 | htmlDataDir defaultCSSFile 224 | copyFile defCssFile (htmlDir defaultCSSFile) 225 | 226 | let highlightOccurrences = htmlOptHighlightOccurrences options 227 | when highlightOccurrences $ do 228 | highlightJsFile <- getDataFileName $ 229 | htmlDataDir occurrenceHighlightJsFile 230 | copyFile highlightJsFile (htmlDir occurrenceHighlightJsFile) 231 | 232 | -- | Converts module names to the corresponding HTML file names. 233 | 234 | modToFile :: TopLevelModuleName -> String -> FilePath 235 | modToFile m ext = render (pretty m) <.> ext 236 | 237 | -- | Generates a highlighted, hyperlinked version of the given module. 238 | 239 | writeRenderedHtml 240 | :: MonadIO m 241 | => Text -- ^ Rendered page 242 | -> FilePath -- ^ Output path. 243 | -> m () 244 | writeRenderedHtml html target = liftIO $ UTF8.writeTextToFile target html 245 | 246 | 247 | -- | Attach multiple Attributes 248 | 249 | (!!) :: Html -> [Attribute] -> Html 250 | h !! as = h ! mconcat as 251 | 252 | -- | Constructs the web page, including headers. 253 | 254 | page :: FilePath -- ^ URL to the CSS file. 255 | -> Bool -- ^ Highlight occurrences 256 | -> Bool -- ^ Whether to reserve literate 257 | -> TopLevelModuleName -- ^ Module to be highlighted. 258 | -> Html 259 | -> Text 260 | page css 261 | highlightOccurrences 262 | htmlHighlight 263 | modName 264 | pageContent = 265 | renderHtml $ if htmlHighlight 266 | then pageContent 267 | else Html5.docTypeHtml $ hdr <> rest 268 | where 269 | 270 | hdr = Html5.head $ mconcat 271 | [ Html5.meta !! [ Attr.charset "utf-8" ] 272 | , Html5.title (toHtml . render $ pretty modName) 273 | , Html5.link !! [ Attr.rel "stylesheet" 274 | , Attr.href $ stringValue css 275 | ] 276 | , if highlightOccurrences 277 | then Html5.script mempty !! 278 | [ Attr.src $ stringValue occurrenceHighlightJsFile 279 | ] 280 | else mempty 281 | ] 282 | 283 | rest = Html5.body $ (Html5.pre ! Attr.class_ "Agda") pageContent 284 | 285 | -- | Position, Contents, Infomation 286 | 287 | type TokenInfo = 288 | ( Int 289 | , String1 290 | , Aspects 291 | ) 292 | 293 | -- | Constructs token stream ready to print. 294 | 295 | tokenStream 296 | :: Text -- ^ The contents of the module. 297 | -> HighlightingInfo -- ^ Highlighting information. 298 | -> [TokenInfo] 299 | tokenStream contents info = 300 | map (\ ((mi, (pos, c)) :| xs) -> 301 | (pos, c :| map (snd . snd) xs, fromMaybe mempty mi)) $ 302 | List1.groupBy ((==) `on` fst) $ 303 | zipWith (\pos c -> (IntMap.lookup pos infoMap, (pos, c))) [1..] (T.unpack contents) 304 | where 305 | infoMap = toMap info 306 | 307 | -- | Constructs the HTML displaying the code. 308 | 309 | code :: ModuleToURL 310 | -> Bool -- ^ Whether to generate non-code contents as-is 311 | -> FileType -- ^ Source file type 312 | -> [TokenInfo] 313 | -> Html 314 | code moduleToURL onlyCode fileType = mconcat . if onlyCode 315 | then case fileType of 316 | -- Explicitly written all cases, so people 317 | -- get compile error when adding new file types 318 | -- when they forget to modify the code here 319 | RstFileType -> map mkRst . splitByMarkup 320 | MdFileType -> map mkMd . splitByMarkup 321 | AgdaFileType -> map mkHtml 322 | OrgFileType -> map mkOrg . splitByMarkup 323 | TreeFileType -> map mkMd . splitByMarkup 324 | -- Two useless cases, probably will never used by anyone 325 | TexFileType -> map mkMd . splitByMarkup 326 | TypstFileType -> map mkMd . splitByMarkup 327 | else map mkHtml 328 | where 329 | trd (_, _, a) = a 330 | 331 | splitByMarkup :: [TokenInfo] -> [[TokenInfo]] 332 | splitByMarkup = splitWhen $ (== Just Markup) . aspect . trd 333 | 334 | mkHtml :: TokenInfo -> Html 335 | mkHtml (pos, s, mi) = 336 | -- Andreas, 2017-06-16, issue #2605: 337 | -- Do not create anchors for whitespace. 338 | applyUnless (mi == mempty) (annotate pos mi) $ toHtml $ List1.toList s 339 | 340 | backgroundOrAgdaToHtml :: TokenInfo -> Html 341 | backgroundOrAgdaToHtml token@(_, s, mi) = case aspect mi of 342 | Just Background -> preEscapedToHtml $ List1.toList s 343 | Just Markup -> __IMPOSSIBLE__ 344 | _ -> mkHtml token 345 | 346 | -- Proposed in #3373, implemented in #3384 347 | mkRst :: [TokenInfo] -> Html 348 | mkRst = mconcat . (toHtml rstDelimiter :) . map backgroundOrAgdaToHtml 349 | 350 | -- The assumption here and in mkOrg is that Background tokens and Agda tokens are always 351 | -- separated by Markup tokens, so these runs only contain one kind. 352 | mkMd :: [TokenInfo] -> Html 353 | mkMd tokens = if containsCode then formatCode else formatNonCode 354 | where 355 | containsCode = any ((/= Just Background) . aspect . trd) tokens 356 | 357 | formatCode = Html5.pre ! Attr.class_ "Agda" $ mconcat $ backgroundOrAgdaToHtml <$> tokens 358 | formatNonCode = mconcat $ backgroundOrAgdaToHtml <$> tokens 359 | 360 | mkOrg :: [TokenInfo] -> Html 361 | mkOrg tokens = mconcat $ if containsCode then formatCode else formatNonCode 362 | where 363 | containsCode = any ((/= Just Background) . aspect . trd) tokens 364 | 365 | startDelimiter = preEscapedToHtml orgDelimiterStart 366 | endDelimiter = preEscapedToHtml orgDelimiterEnd 367 | 368 | formatCode = startDelimiter : foldr (\x -> (backgroundOrAgdaToHtml x :)) [endDelimiter] tokens 369 | formatNonCode = map backgroundOrAgdaToHtml tokens 370 | 371 | -- Put anchors that enable referencing that token. 372 | -- We put a fail safe numeric anchor (file position) for internal references 373 | -- (issue #2756), as well as a heuristic name anchor for external references 374 | -- (issue #2604). 375 | annotate :: Int -> Aspects -> Html -> Html 376 | annotate pos mi = 377 | applyWhen hereAnchor (anchorage nameAttributes mempty <>) . anchorage posAttributes 378 | where 379 | -- Warp an anchor ( tag) with the given attributes around some HTML. 380 | anchorage :: [Attribute] -> Html -> Html 381 | anchorage attrs html = Html5.a html !! attrs 382 | 383 | -- File position anchor (unique, reliable). 384 | posAttributes :: [Attribute] 385 | posAttributes = concat 386 | [ [Attr.id $ stringValue $ show pos ] 387 | , toList $ link <$> definitionSite mi 388 | , Attr.class_ (stringValue $ unwords classes) <$ guard (not $ null classes) 389 | ] 390 | 391 | -- Named anchor (not reliable, but useful in the general case for outside refs). 392 | nameAttributes :: [Attribute] 393 | nameAttributes = [ Attr.id $ stringValue $ fromMaybe __IMPOSSIBLE__ $ mDefSiteAnchor ] 394 | 395 | classes = concat 396 | [ concatMap noteClasses (note mi) 397 | , otherAspectClasses (toList $ otherAspects mi) 398 | , concatMap aspectClasses (aspect mi) 399 | ] 400 | 401 | aspectClasses (Name mKind op) = kindClass ++ opClass 402 | where 403 | kindClass = toList $ fmap showKind mKind 404 | 405 | showKind (Constructor Inductive) = "InductiveConstructor" 406 | showKind (Constructor CoInductive) = "CoinductiveConstructor" 407 | showKind k = show k 408 | 409 | opClass = ["Operator" | op] 410 | aspectClasses a = [show a] 411 | 412 | 413 | otherAspectClasses = map show 414 | 415 | -- Notes are not included. 416 | noteClasses _s = [] 417 | 418 | -- Should we output a named anchor? 419 | -- Only if we are at the definition site now (@here@) 420 | -- and such a pretty named anchor exists (see 'defSiteAnchor'). 421 | hereAnchor :: Bool 422 | hereAnchor = here && isJust mDefSiteAnchor 423 | 424 | mDefinitionSite :: Maybe DefinitionSite 425 | mDefinitionSite = definitionSite mi 426 | 427 | -- Are we at the definition site now? 428 | here :: Bool 429 | here = maybe False defSiteHere mDefinitionSite 430 | 431 | mDefSiteAnchor :: Maybe String 432 | mDefSiteAnchor = maybe __IMPOSSIBLE__ defSiteAnchor mDefinitionSite 433 | 434 | link (DefinitionSite m defPos _here aName) = Attr.href $ stringValue $ 435 | -- If the definition site points to the top of a file, 436 | -- we drop the anchor part and just link to the file. 437 | applyUnless (defPos <= 1) 438 | (++ "#" ++ Network.URI.Encode.encode anchor) 439 | (maybe id () u $ Network.URI.Encode.encode $ modToFile m "") 440 | where 441 | u = Map.lookup m moduleToURL 442 | -- Use named anchors for external links as they should be more stable(?) 443 | anchor | Just a <- aName, Just u' <- u, u' /= "" = a 444 | | otherwise = show defPos 445 | -------------------------------------------------------------------------------- /shake/LICENSE.agda: -------------------------------------------------------------------------------- 1 | The files under HTML/ are modified versions of Agda's HTML backend. 2 | Agda is distributed with the following license: 3 | 4 | Copyright (c) 2005-2024 remains with the authors. 5 | Agda 2 was originally written by Ulf Norell, 6 | partially based on code from Agda 1 by Catarina Coquand and Makoto Takeyama, 7 | and from Agdalight by Ulf Norell and Andreas Abel. 8 | Cubical Agda was originally contributed by Andrea Vezzosi. 9 | 10 | Agda 2 is currently actively developed mainly by Andreas Abel, 11 | Guillaume Allais, Liang-Ting Chen, Jesper Cockx, Matthew Daggitt, 12 | Nils Anders Danielsson, Amélia Liao, Ulf Norell, and 13 | Andrés Sicard-Ramírez. 14 | 15 | Further, Agda 2 has received contributions by, amongst others, 16 | Arthur Adjedj, Stevan Andjelkovic, 17 | Marcin Benke, Jean-Philippe Bernardy, Guillaume Brunerie, 18 | James Chapman, Jonathan Coates, 19 | Dominique Devriese, Péter Diviánszky, Robert Estelle, 20 | Olle Fredriksson, Adam Gundry, Daniel Gustafsson, Philipp Hausmann, 21 | Alan Jeffrey, Phil de Joux, 22 | Wolfram Kahl, Wen Kokke, John Leo, Fredrik Lindblad, 23 | Víctor López Juan, Ting-Gan Lua, Francesco Mazzoli, Stefan Monnier, 24 | Guilhem Moulin, Konstantin Nisht, Fredrik Nordvall Forsberg, 25 | Josselin Poiret, Nicolas Pouillard, Jonathan Prieto, Christian Sattler, 26 | Makoto Takeyama, Andrea Vezzosi, Noam Zeilberger, and Tesla Ice Zhang. 27 | The full list of contributors is available at 28 | https://github.com/agda/agda/graphs/contributors or from the git 29 | repository via ``git shortlog -sne``. 30 | 31 | Permission is hereby granted, free of charge, to any person obtaining 32 | a copy of this software and associated documentation files (the 33 | "Software"), to deal in the Software without restriction, including 34 | without limitation the rights to use, copy, modify, merge, publish, 35 | distribute, sublicense, and/or sell copies of the Software, and to 36 | permit persons to whom the Software is furnished to do so, subject to 37 | the following conditions: 38 | 39 | The above copyright notice and this permission notice shall be 40 | included in all copies or substantial portions of the Software. 41 | 42 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 43 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 44 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 45 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 46 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 47 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 48 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 49 | -------------------------------------------------------------------------------- /shake/Main.hs: -------------------------------------------------------------------------------- 1 | import Agda.Compiler.Backend hiding (getEnv) 2 | import Agda.Interaction.Imports 3 | import Agda.Interaction.Library.Base 4 | import Agda.Interaction.Options 5 | import Agda.TypeChecking.Errors 6 | import Agda.Utils.FileName 7 | import Agda.Utils.Monad 8 | 9 | import Control.Monad.Error.Class 10 | 11 | import Data.Foldable 12 | import Data.List 13 | import Data.Map qualified as Map 14 | import Data.Text qualified as T 15 | 16 | import Development.Shake 17 | import Development.Shake.Classes 18 | import Development.Shake.FilePath 19 | 20 | import HTML.Backend 21 | import HTML.Base 22 | 23 | import Text.HTML.TagSoup 24 | import Text.Pandoc 25 | import Text.Pandoc.Walk 26 | 27 | newtype CompileDirectory = CompileDirectory (FilePath, FilePath) 28 | deriving (Show, Typeable, Eq, Hashable, Binary, NFData) 29 | type instance RuleResult CompileDirectory = () 30 | 31 | sourceDir, source1labDir, buildDir, htmlDir, siteDir, everything, everything1lab :: FilePath 32 | sourceDir = "src" 33 | source1labDir = "src-1lab" 34 | buildDir = "_build" 35 | htmlDir = buildDir "html" 36 | siteDir = buildDir "site" 37 | everything = sourceDir "Everything.agda" 38 | everything1lab = source1labDir "Everything-1lab.agda" 39 | 40 | myHtmlBackend :: Backend 41 | myHtmlBackend = Backend htmlBackend' 42 | { options = initialHtmlFlags 43 | { htmlFlagDir = htmlDir 44 | , htmlFlagHighlightOccurrences = True 45 | , htmlFlagCssFile = Just "style.css" 46 | , htmlFlagHighlight = HighlightCode 47 | , htmlFlagLibToURL = \ (LibName lib version) -> 48 | let v = intercalate "." (map show version) in 49 | Map.lookup lib $ Map.fromList 50 | [ ("agda-builtins", "https://agda.github.io/agda-stdlib/master") 51 | , ("standard-library", "https://agda.github.io/agda-stdlib/v" <> v) 52 | , ("cubical", "https://agda.github.io/cubical") 53 | , ("1lab", "https://1lab.dev") 54 | , ("cubical-experiments", "") 55 | ] 56 | } 57 | } 58 | 59 | filenameToModule :: FilePath -> String 60 | filenameToModule f = dropExtensions f 61 | 62 | makeEverythingFile :: [FilePath] -> String 63 | makeEverythingFile = unlines . map (\ m -> "import " <> filenameToModule m) 64 | 65 | readFileText :: FilePath -> Action T.Text 66 | readFileText = fmap T.pack . readFile' 67 | 68 | importToModule :: String -> String 69 | importToModule s = innerText tags 70 | where tags = parseTags s 71 | 72 | patchBlock :: Block -> Block 73 | -- Add anchor links next to headers 74 | patchBlock (Header i a@(ident, _, _) inl) | ident /= "" = Header i a $ 75 | inl ++ [Link ("", ["anchor"], [("aria-hidden", "true")]) [] ("#" <> ident, "")] 76 | patchBlock b = b 77 | 78 | main :: IO () 79 | main = shakeArgs shakeOptions do 80 | -- I realise this is not how a Shakefile should be structured, but I got 81 | -- bored trying to figure it out and this is good enough for now. 82 | -- I should probably look into Development.Shake.Forward ... 83 | compileModule <- addOracle \ (CompileDirectory (sourceDir, everything)) -> do 84 | librariesFile <- getEnv "AGDA_LIBRARIES_FILE" 85 | sourceFiles <- filter (not . ("Everything*" ?==)) <$> 86 | getDirectoryFiles sourceDir ["//*.agda", "//*.lagda.md"] 87 | writeFile' everything (makeEverythingFile sourceFiles) 88 | traced "agda" do 89 | root <- absolute sourceDir 90 | runTCMTopPrettyErrors do 91 | setCommandLineOptions' root defaultOptions 92 | { optOverrideLibrariesFile = librariesFile 93 | , optDefaultLibs = False 94 | } 95 | stBackends `setTCLens` [myHtmlBackend] 96 | sourceFile <- srcFromPath =<< liftIO (absolute everything) 97 | source <- parseSource sourceFile 98 | checkResult <- typeCheckMain TypeCheck source 99 | callBackend "HTML" IsMain checkResult 100 | moduleTemplate <- readFileText "module.html" 101 | for_ sourceFiles \ sourceFile -> do 102 | let 103 | htmlFile = dropExtensions sourceFile <.> "html" 104 | literateFile = dropExtensions sourceFile <.> takeExtension sourceFile -- .lagda.md → .md 105 | contents <- case takeExtensions sourceFile of 106 | ".lagda.md" -> do 107 | markdown <- readFileText (htmlDir literateFile) 108 | traced "pandoc" $ runIOorExplode do 109 | pandoc <- readMarkdown def { 110 | readerExtensions = foldr enableExtension pandocExtensions [Ext_autolink_bare_uris] 111 | } markdown 112 | pandoc <- pure $ walk patchBlock pandoc 113 | writeHtml5String def pandoc 114 | ".agda" -> do 115 | html <- readFileText (htmlDir htmlFile) 116 | pure $ "
" <> html <> "
" 117 | _ -> fail ("unknown extension for file " <> sourceFile) 118 | writeFile' (siteDir htmlFile) 119 | $ T.unpack 120 | $ T.replace "@contents@" contents 121 | $ T.replace "@moduleName@" (T.pack $ filenameToModule sourceFile) 122 | $ T.replace "@path@" (T.pack $ sourceDir sourceFile) 123 | $ moduleTemplate 124 | 125 | siteDir "index.html" %> \ index -> do 126 | compileModule (CompileDirectory (sourceDir, everything)) 127 | compileModule (CompileDirectory (source1labDir, everything1lab)) 128 | indexTemplate <- readFileText "index.html" 129 | everythingAgda <- (<>) 130 | <$> readFileLines (htmlDir "Everything.html") 131 | <*> readFileLines (htmlDir "Everything-1lab.html") 132 | writeFile' index 133 | $ T.unpack 134 | $ T.replace "@contents@" (T.pack $ unlines $ sortOn importToModule $ everythingAgda) 135 | $ indexTemplate 136 | copyFile' "style.css" (siteDir "style.css") 137 | copyFile' "main.js" (siteDir "main.js") 138 | copyFile' (htmlDir "highlight-hover.js") (siteDir "highlight-hover.js") 139 | 140 | phony "all" do 141 | need [siteDir "index.html"] 142 | 143 | want ["all"] 144 | 145 | runTCMTopPrettyErrors :: TCM a -> IO a 146 | runTCMTopPrettyErrors tcm = do 147 | r <- runTCMTop' $ (Just <$> tcm) `catchError` \err -> do 148 | warnings <- fmap (map show) . prettyTCWarnings' =<< getAllWarningsOfTCErr err 149 | errors <- show <$> prettyError err 150 | let everything = filter (not . null) $ warnings ++ [errors] 151 | unless (null errors) . liftIO . putStr $ unlines everything 152 | pure Nothing 153 | 154 | maybe (fail "Agda compilation failed") pure r 155 | -------------------------------------------------------------------------------- /shake/cubical-experiments-shake.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 3.4 2 | name: cubical-experiments-shake 3 | version: 0.1.0.0 4 | license: AGPL-3.0-or-later 5 | author: Naïm Favier 6 | maintainer: n@monade.li 7 | category: Development 8 | build-type: Simple 9 | 10 | executable cubical-experiments-shake 11 | ghc-options: -Wall -Wno-name-shadowing 12 | main-is: Main.hs 13 | other-modules: HTML.Base, 14 | HTML.Backend, 15 | build-depends: base, 16 | Agda, 17 | shake, 18 | blaze-html, 19 | containers, 20 | deepseq, 21 | directory, 22 | filepath, 23 | mtl, 24 | pandoc, 25 | pandoc-types, 26 | regex-tdfa, 27 | silently, 28 | split, 29 | tagsoup, 30 | text, 31 | transformers, 32 | uri-encode, 33 | hs-source-dirs: . 34 | default-language: GHC2021 35 | default-extensions: 36 | BangPatterns 37 | BlockArguments 38 | ConstraintKinds 39 | DefaultSignatures 40 | DeriveFoldable 41 | DeriveFunctor 42 | DeriveGeneric 43 | DeriveTraversable 44 | DerivingStrategies 45 | ExistentialQuantification 46 | FlexibleContexts 47 | FlexibleInstances 48 | FunctionalDependencies 49 | GADTs 50 | GeneralizedNewtypeDeriving 51 | InstanceSigs 52 | LambdaCase 53 | MultiParamTypeClasses 54 | MultiWayIf 55 | NamedFieldPuns 56 | OverloadedStrings 57 | PatternSynonyms 58 | RankNTypes 59 | RecordWildCards 60 | ScopedTypeVariables 61 | StandaloneDeriving 62 | TupleSections 63 | TypeFamilies 64 | TypeOperators 65 | TypeSynonymInstances 66 | ViewPatterns 67 | -------------------------------------------------------------------------------- /src-1lab/AdjunctionCommaIso.agda: -------------------------------------------------------------------------------- 1 | open import Cat.Functor.Adjoint 2 | open import Cat.Functor.Equivalence 3 | open import Cat.Instances.Comma 4 | open import Cat.Prelude 5 | 6 | import Cat.Reasoning 7 | 8 | open ↓Hom 9 | open ↓Obj 10 | open Functor 11 | open is-iso 12 | open is-precat-iso 13 | 14 | -- An adjunction F ⊣ G induces an isomorphism of comma categories F ↓ 1 ≅ 1 ↓ G 15 | module AdjunctionCommaIso where 16 | 17 | module _ 18 | {oc ℓc od ℓd} {C : Precategory oc ℓc} {D : Precategory od ℓd} 19 | {F : Functor C D} {G : Functor D C} (F⊣G : F ⊣ G) 20 | where 21 | 22 | module C = Cat.Reasoning C 23 | module D = Cat.Reasoning D 24 | 25 | to : Functor (F ↓ Id) (Id ↓ G) 26 | to .F₀ o .x = o .x 27 | to .F₀ o .y = o .y 28 | to .F₀ o .map = L-adjunct F⊣G (o .map) 29 | to .F₁ f .α = f .α 30 | to .F₁ f .β = f .β 31 | to .F₁ {a} {b} f .sq = 32 | L-adjunct F⊣G (b .map) C.∘ f .α ≡˘⟨ L-adjunct-naturall F⊣G _ _ ⟩ 33 | L-adjunct F⊣G (b .map D.∘ F .F₁ (f .α)) ≡⟨ ap (L-adjunct F⊣G) (f .sq) ⟩ 34 | L-adjunct F⊣G (f .β D.∘ a .map) ≡⟨ L-adjunct-naturalr F⊣G _ _ ⟩ 35 | G .F₁ (f .β) C.∘ L-adjunct F⊣G (a .map) ∎ 36 | to .F-id = trivial! 37 | to .F-∘ _ _ = trivial! 38 | 39 | to-is-precat-iso : is-precat-iso to 40 | to-is-precat-iso .has-is-ff = is-iso→is-equiv is where 41 | is : ∀ {a b} → is-iso (to .F₁ {a} {b}) 42 | is .from f .α = f .α 43 | is .from f .β = f .β 44 | is {a} {b} .from f .sq = Equiv.injective (adjunct-hom-equiv F⊣G) $ 45 | L-adjunct F⊣G (b .map D.∘ F .F₁ (f .α)) ≡⟨ L-adjunct-naturall F⊣G _ _ ⟩ 46 | L-adjunct F⊣G (b .map) C.∘ f .α ≡⟨ f .sq ⟩ 47 | G .F₁ (f .β) C.∘ L-adjunct F⊣G (a .map) ≡˘⟨ L-adjunct-naturalr F⊣G _ _ ⟩ 48 | L-adjunct F⊣G (f .β D.∘ a .map) ∎ 49 | is .rinv f = trivial! 50 | is .linv f = trivial! 51 | to-is-precat-iso .has-is-iso = is-iso→is-equiv is where 52 | is : is-iso (to .F₀) 53 | is .from o .x = o .x 54 | is .from o .y = o .y 55 | is .from o .map = R-adjunct F⊣G (o .map) 56 | is .rinv o = ↓Obj-path _ _ refl refl (L-R-adjunct F⊣G _) 57 | is .linv o = ↓Obj-path _ _ refl refl (R-L-adjunct F⊣G _) 58 | -------------------------------------------------------------------------------- /src-1lab/Applicative.agda: -------------------------------------------------------------------------------- 1 | open import 1Lab.Equiv 2 | open import 1Lab.Extensionality 3 | open import 1Lab.HLevel 4 | open import 1Lab.HLevel.Closure 5 | open import 1Lab.Path 6 | open import 1Lab.Reflection.HLevel 7 | open import 1Lab.Reflection.Record 8 | open import 1Lab.Type 9 | open import 1Lab.Type.Sigma 10 | 11 | -- Applicative fully determines the underlying Functor. 12 | module Applicative {ℓ} where 13 | 14 | private variable 15 | A B C : Type ℓ 16 | 17 | _∘'_ : ∀ {ℓ₁ ℓ₂ ℓ₃} {A : Type ℓ₁} {B : Type ℓ₂} {C : Type ℓ₃} 18 | → (B → C) → (A → B) → A → C 19 | f ∘' g = λ z → f (g z) 20 | 21 | record applicative (F : Type ℓ → Type ℓ) : Type (lsuc ℓ) where 22 | infixl 8 _<*>_ 23 | field 24 | sets : is-set (F A) 25 | pure : A → F A 26 | _<*>_ : F (A → B) → F A → F B 27 | <*>-identity : ∀ {u : F A} 28 | → pure id <*> u ≡ u 29 | <*>-composition : ∀ {u : F (B → C)} {v : F (A → B)} {w : F A} 30 | → pure _∘'_ <*> u <*> v <*> w ≡ u <*> (v <*> w) 31 | <*>-homomorphism : ∀ {f : A → B} {x : A} 32 | → pure f <*> pure x ≡ pure (f x) 33 | <*>-interchange : ∀ {u : F (A → B)} {x : A} 34 | → u <*> pure x ≡ pure (λ f → f x) <*> u 35 | 36 | record applicative-functor (F : Type ℓ → Type ℓ) (app : applicative F) : Type (lsuc ℓ) where 37 | open applicative app 38 | infixl 8 _<$>_ 39 | field 40 | _<$>_ : (A → B) → F A → F B 41 | <$>-identity : ∀ {x : F A} 42 | → id <$> x ≡ x 43 | <$>-composition : ∀ {f : B → C} {g : A → B} {x : F A} 44 | → f <$> (g <$> x) ≡ f ∘' g <$> x 45 | pure-natural : ∀ {f : A → B} {x : A} 46 | → f <$> pure x ≡ pure (f x) 47 | <*>-extranatural-A : ∀ {f : F (B → C)} {g : A → B} {x : F A} 48 | → f <*> (g <$> x) ≡ (_∘' g) <$> f <*> x 49 | <*>-natural-B : ∀ {g : B → C} {f : F (A → B)} {x : F A} 50 | → g <$> (f <*> x) ≡ (g ∘'_) <$> f <*> x 51 | 52 | open applicative-functor 53 | unquoteDecl eqv = declare-record-iso eqv (quote applicative-functor) 54 | 55 | applicative-functor-path 56 | : ∀ {F : Type ℓ → Type ℓ} {app} {a b : applicative-functor F app} 57 | → (∀ {A B} (f : A → B) x → a ._<$>_ f x ≡ b ._<$>_ f x) 58 | → a ≡ b 59 | applicative-functor-path {F = F} {app = app} p = Iso.injective eqv (Σ-prop-path! (ext λ f → p f)) 60 | where instance 61 | F-sets : ∀ {x} → H-Level (F x) 2 62 | F-sets = hlevel-instance (app .applicative.sets) 63 | 64 | applicative-determines-functor : ∀ {F} (app : applicative F) 65 | → is-contr (applicative-functor F app) 66 | applicative-determines-functor {F} app = p where 67 | open applicative app 68 | p : is-contr (applicative-functor F app) 69 | p .centre ._<$>_ f x = pure f <*> x 70 | p .centre .<$>-identity = <*>-identity 71 | p .centre .<$>-composition {f = f} {g = g} {x = x} = 72 | pure f <*> (pure g <*> x) ≡⟨ sym <*>-composition ⟩ 73 | pure _∘'_ <*> pure f <*> pure g <*> x ≡⟨ ap (λ y → y <*> pure g <*> x) <*>-homomorphism ⟩ 74 | pure (f ∘'_) <*> pure g <*> x ≡⟨ ap (_<*> x) <*>-homomorphism ⟩ 75 | pure (f ∘' g) <*> x ∎ 76 | p .centre .pure-natural = <*>-homomorphism 77 | p .centre .<*>-extranatural-A {f = f} {g = g} {x = x} = 78 | f <*> (pure g <*> x) ≡⟨ sym <*>-composition ⟩ 79 | pure _∘'_ <*> f <*> pure g <*> x ≡⟨ ap (_<*> x) <*>-interchange ⟩ 80 | pure (_$ g) <*> (pure _∘'_ <*> f) <*> x ≡⟨ ap (_<*> x) (p .centre .<$>-composition) ⟩ 81 | pure (_∘' g) <*> f <*> x ∎ 82 | p .centre .<*>-natural-B {g = g} {f = f} {x = x} = 83 | pure g <*> (f <*> x) ≡⟨ sym <*>-composition ⟩ 84 | pure _∘'_ <*> pure g <*> f <*> x ≡⟨ ap (λ y → y <*> f <*> x) <*>-homomorphism ⟩ 85 | pure (g ∘'_) <*> f <*> x ∎ 86 | p .paths app' = applicative-functor-path λ f x → 87 | pure f <*> x ≡⟨ ap (_<*> x) (sym A.pure-natural) ⟩ 88 | (f ∘'_) A.<$> pure id <*> x ≡˘⟨ A.<*>-natural-B ⟩ 89 | f A.<$> (pure id <*> x) ≡⟨ ap (f A.<$>_) <*>-identity ⟩ 90 | f A.<$> x ∎ 91 | where module A = applicative-functor app' 92 | -------------------------------------------------------------------------------- /src-1lab/CoherentlyConstant.agda: -------------------------------------------------------------------------------- 1 | open import 1Lab.Prelude hiding (∥_∥³; ∥-∥³-elim-set; ∥-∥³-elim-prop; ∥-∥³-rec; ∥-∥³-is-prop; ∥-∥-rec-groupoid) 2 | open import 1Lab.Path.Reasoning 3 | 4 | -- Coherently constant maps into groupoids, now at https://1lab.dev/1Lab.HIT.Truncation.html#maps-into-groupoids 5 | module CoherentlyConstant where 6 | 7 | data ∥_∥³ {ℓ} (A : Type ℓ) : Type ℓ where 8 | inc : A → ∥ A ∥³ 9 | iconst : ∀ a b → inc a ≡ inc b 10 | icoh : ∀ a b c → PathP (λ i → inc a ≡ iconst b c i) (iconst a b) (iconst a c) 11 | squash : is-groupoid ∥ A ∥³ 12 | 13 | ∥-∥³-elim-set 14 | : ∀ {ℓ ℓ'} {A : Type ℓ} {P : ∥ A ∥³ → Type ℓ'} 15 | → (∀ a → is-set (P a)) 16 | → (f : (a : A) → P (inc a)) 17 | → (∀ a b → PathP (λ i → P (iconst a b i)) (f a) (f b)) 18 | → ∀ a → P a 19 | ∥-∥³-elim-set {P = P} sets f fconst = go where 20 | go : ∀ a → P a 21 | go (inc x) = f x 22 | go (iconst a b i) = fconst a b i 23 | go (icoh a b c i j) = is-set→squarep (λ i j → sets (icoh a b c i j)) 24 | refl (λ i → go (iconst a b i)) (λ i → go (iconst a c i)) (λ i → go (iconst b c i)) 25 | i j 26 | go (squash a b p q r s i j k) = is-hlevel→is-hlevel-dep 2 (λ _ → is-hlevel-suc 2 (sets _)) 27 | (go a) (go b) 28 | (λ k → go (p k)) (λ k → go (q k)) 29 | (λ j k → go (r j k)) (λ j k → go (s j k)) 30 | (squash a b p q r s) i j k 31 | 32 | ∥-∥³-elim-prop 33 | : ∀ {ℓ ℓ'} {A : Type ℓ} {P : ∥ A ∥³ → Type ℓ'} 34 | → (∀ a → is-prop (P a)) 35 | → (f : (a : A) → P (inc a)) 36 | → ∀ a → P a 37 | ∥-∥³-elim-prop props f = ∥-∥³-elim-set (λ _ → is-hlevel-suc 1 (props _)) f 38 | (λ _ _ → is-prop→pathp (λ _ → props _) _ _) 39 | 40 | ∥-∥³-rec 41 | : ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} 42 | → is-groupoid B 43 | → (f : A → B) 44 | → (fconst : ∀ x y → f x ≡ f y) 45 | → (∀ x y z → fconst x y ∙ fconst y z ≡ fconst x z) 46 | → ∥ A ∥³ → B 47 | ∥-∥³-rec {A = A} {B} bgrpd f fconst fcoh = go where 48 | go : ∥ A ∥³ → B 49 | go (inc x) = f x 50 | go (iconst a b i) = fconst a b i 51 | go (icoh a b c i j) = ∙→square (sym (fcoh a b c)) i j 52 | go (squash x y a b p q i j k) = bgrpd 53 | (go x) (go y) 54 | (λ i → go (a i)) (λ i → go (b i)) 55 | (λ i j → go (p i j)) (λ i j → go (q i j)) 56 | i j k 57 | 58 | ∥-∥³-is-prop : ∀ {ℓ} {A : Type ℓ} → is-prop ∥ A ∥³ 59 | ∥-∥³-is-prop = is-contr-if-inhabited→is-prop $ 60 | ∥-∥³-elim-prop (λ _ → hlevel 1) 61 | (λ a → contr (inc a) (∥-∥³-elim-set (λ _ → squash _ _) (iconst a) (icoh a))) 62 | 63 | ∥-∥-rec-groupoid 64 | : ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} 65 | → is-groupoid B 66 | → (f : A → B) 67 | → (fconst : ∀ x y → f x ≡ f y) 68 | → (∀ x y z → fconst x y ∙ fconst y z ≡ fconst x z) 69 | → ∥ A ∥ → B 70 | ∥-∥-rec-groupoid bgrpd f fconst fcoh = 71 | ∥-∥³-rec bgrpd f fconst fcoh ∘ ∥-∥-rec ∥-∥³-is-prop inc 72 | -------------------------------------------------------------------------------- /src-1lab/EasyParametricity.lagda.md: -------------------------------------------------------------------------------- 1 |
2 | Imports 3 | 4 | ```agda 5 | open import Cat.Prelude hiding (J) 6 | open import Cat.Diagram.Limit.Base 7 | open import Cat.Instances.Discrete 8 | open import Cat.Instances.Shape.Join 9 | open import Cat.Instances.Product 10 | 11 | open import Data.Sum 12 | 13 | import Cat.Reasoning 14 | import Cat.Functor.Reasoning 15 | import Cat.Functor.Bifunctor 16 | 17 | open Precategory 18 | open Functor 19 | open make-is-limit 20 | ``` 21 |
22 | 23 | This module formalises a few very interesting results from Jem Lord's recent work on 24 | [*Easy Parametricity*](https://hott-uf.github.io/2025/abstracts/HoTTUF_2025_paper_21.pdf), 25 | presented at [HoTT/UF 2025](https://hott-uf.github.io/2025/). 26 | 27 | ```agda 28 | module EasyParametricity {u} where 29 | 30 | U = Type u 31 | 𝟘 = Lift u ⊥ 32 | 𝟙 = Lift u ⊤ 33 | 34 | -- We think of functions f : U → A as "bridges" from f 𝟘 to f 𝟙. 35 | record Bridge {ℓ} (A : Type ℓ) (x y : A) : Type (ℓ ⊔ lsuc u) where 36 | no-eta-equality 37 | constructor bridge 38 | pattern 39 | field 40 | app : U → A 41 | app𝟘 : app 𝟘 ≡ x 42 | app𝟙 : app 𝟙 ≡ y 43 | 44 | -- Every function preserves bridges. 45 | ap-bridge 46 | : ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} (f : A → B) {x y : A} 47 | → Bridge A x y → Bridge B (f x) (f y) 48 | ap-bridge f (bridge app app𝟘 app𝟙) = bridge (f ⊙ app) (ap f app𝟘) (ap f app𝟙) 49 | 50 | postulate 51 | -- An immediate consequence of Jem Lord's parametricity axiom: a function 52 | -- out of U into a U-small type cannot tell 0 and 1 apart; this is all we need here. 53 | -- In other words, U-small types are bridge-discrete. 54 | parametricity : ∀ {A : U} {x y : A} → Bridge A x y → x ≡ y 55 | 56 | -- The type of formal composites r ∘ l : A → B in C. We want to think of this 57 | -- as the type of factorisations of some morphism f : A → B, but it turns out 58 | -- to be unnecessary to track f in the type. 59 | record Factorisation {o ℓ} (C : Precategory o ℓ) (A B : C .Ob) : Type (o ⊔ ℓ) where 60 | constructor factor 61 | module C = Precategory C 62 | field 63 | X : C.Ob 64 | l : C.Hom A X 65 | r : C.Hom X B 66 | 67 | module _ 68 | {o ℓ} {C : Precategory o ℓ} 69 | (let module C = Precategory C) 70 | where 71 | 72 | module _ {A B : C.Ob} (f : C.Hom A B) where 73 | 74 | -- The two factorisations id ∘ f and f ∘ id. 75 | _∘id id∘_ : Factorisation C A B 76 | _∘id = factor A C.id f 77 | id∘_ = factor B f C.id 78 | 79 | module _ 80 | (C-complete : is-complete u lzero C) 81 | (C-category : is-category C) 82 | {A B : C.Ob} (f : C.Hom A B) 83 | where 84 | 85 | -- In a U-complete univalent category, every type of factorisations is bridge-codiscrete. 86 | -- We define a bridge from id ∘ f to f ∘ id. 87 | 88 | factorisation-bridge : Bridge (Factorisation C A B) (id∘ f) (f ∘id) 89 | factorisation-bridge = bridge b b0 b1 where 90 | 91 | b : U → Factorisation C A B 92 | b P = fac (C-complete diagram) module b where 93 | 94 | -- This is the interesting part: given a type P : U, we construct the 95 | -- wide pullback of P-many copies of f. 96 | -- Since we only care about the cases where P is a proposition, we 97 | -- can just take the discrete or codiscrete category on P and adjoin a 98 | -- terminal object to get our diagram shape. 99 | J : Precategory u lzero 100 | J = Codisc' P ▹ 101 | 102 | diagram : Functor J C 103 | diagram .F₀ (inl _) = A 104 | diagram .F₀ (inr _) = B 105 | diagram .F₁ {inl _} {inl _} _ = C.id 106 | diagram .F₁ {inl _} {inr _} _ = f 107 | diagram .F₁ {inr _} {inr _} _ = C.id 108 | diagram .F-id {inl _} = refl 109 | diagram .F-id {inr _} = refl 110 | diagram .F-∘ {inl _} {inl _} {inl _} _ _ = sym (C.idl _) 111 | diagram .F-∘ {inl _} {inl _} {inr _} _ _ = sym (C.idr _) 112 | diagram .F-∘ {inl _} {inr _} {inr _} _ _ = sym (C.idl _) 113 | diagram .F-∘ {inr _} {inr _} {inr _} _ _ = sym (C.idl _) 114 | 115 | -- Given a limit of this diagram (which exists by the assumption of U-completeness), 116 | -- we get a factorisation of f as the universal map followed by the projection to B. 117 | fac : Limit diagram → Factorisation C A B 118 | fac lim = factor X l r where 119 | module lim = Limit lim 120 | X : C.Ob 121 | X = lim.apex 122 | l : C.Hom A X 123 | l = lim.universal (λ { (inl _) → C.id; (inr _) → f }) λ where 124 | {inl _} {inl _} _ → C.idl _ 125 | {inl _} {inr _} _ → C.idr _ 126 | {inr _} {inr _} _ → C.idl _ 127 | r : C.Hom X B 128 | r = lim.cone ._=>_.η (inr tt) 129 | 130 | -- We check that the endpoints of the bridge are what we expect: when P 131 | -- is empty, we are taking the limit of the single-object diagram B, so 132 | -- our factorisation is A → B → B. 133 | b0 : b 𝟘 ≡ id∘ f 134 | b0 = ap (b.fac 𝟘) (Limit-is-prop C-category (C-complete _) (to-limit lim)) where 135 | lim : is-limit (b.diagram 𝟘) B _ 136 | lim = to-is-limit λ where 137 | .ψ (inr _) → C.id 138 | .commutes {inr _} {inr _} _ → C.idl _ 139 | .universal eps comm → eps (inr _) 140 | .factors {inr _} eps comm → C.idl _ 141 | .unique eps comm other fac → sym (C.idl _) ∙ fac (inr _) 142 | 143 | -- When P is contractible, we are taking the limit of the arrow diagram 144 | -- A → B, so our factorisation is A → A → B. 145 | b1 : b 𝟙 ≡ f ∘id 146 | b1 = ap (b.fac 𝟙) (Limit-is-prop C-category (C-complete _) (to-limit lim)) where 147 | lim : is-limit (b.diagram 𝟙) A _ 148 | lim = to-is-limit λ where 149 | .ψ (inl _) → C.id 150 | .ψ (inr _) → f 151 | .commutes {inl _} {inl _} _ → C.idl _ 152 | .commutes {inl _} {inr _} _ → C.idr _ 153 | .commutes {inr _} {inr _} _ → C.idl _ 154 | .universal eps comm → eps (inl (lift tt)) 155 | .factors {inl _} eps comm → C.idl _ 156 | .factors {inr _} eps comm → comm {inl _} {inr _} _ 157 | .unique eps comm other fac → sym (C.idl _) ∙ fac (inl _) 158 | 159 | -- Theorem 1: let C be a U-complete univalent category and D a locally 160 | -- U-small category. 161 | module _ 162 | {o o' ℓ} {C : Precategory o ℓ} {D : Precategory o' u} 163 | (let module C = Cat.Reasoning C) (let module D = Cat.Reasoning D) 164 | (C-complete : is-complete u lzero C) 165 | (C-category : is-category C) 166 | where 167 | 168 | -- 1.a: naturality of transformations between functors C → D is free. 169 | -- (This is a special case of 1.b.) 170 | module _ 171 | (F G : Functor C D) 172 | (let module F = Cat.Functor.Reasoning F) (let module G = Cat.Functor.Reasoning G) 173 | (η : ∀ x → D.Hom (F.₀ x) (G.₀ x)) 174 | where 175 | 176 | natural : is-natural-transformation F G η 177 | natural A B f = G.introl refl ∙ z0≡z1 ∙ (D.refl⟩∘⟨ F.elimr refl) where 178 | 179 | -- Given a factorisation A → X → B, we define the map 180 | -- F A 181 | -- ↓ 182 | -- η X : F X → G X 183 | -- ↓ 184 | -- G B 185 | -- which recovers the naturality square for f as the factorisation varies 186 | -- from id ∘ f to f ∘ id. 187 | z : Factorisation C A B → D.Hom (F.₀ A) (G.₀ B) 188 | z (factor X l r) = G.₁ r D.∘ η X D.∘ F.₁ l 189 | 190 | -- As a result, we get a bridge from one side of the naturality square 191 | -- to the other; since D is locally U-small, the Hom-sets of D are bridge-discrete, 192 | -- so we get the desired equality. 193 | z0≡z1 : z (id∘ f) ≡ z (f ∘id) 194 | z0≡z1 = parametricity (ap-bridge z (factorisation-bridge C-complete C-category f)) 195 | 196 | -- 1.b: dinaturality of transformations between bifunctors C^op × C → D is free. 197 | module _ 198 | (F G : Functor (C ^op ×ᶜ C) D) 199 | (let module F = Cat.Functor.Bifunctor F) (let module G = Cat.Functor.Bifunctor G) 200 | (η : ∀ x → D.Hom (F.₀ (x , x)) (G.₀ (x , x))) 201 | where 202 | 203 | dinatural 204 | : ∀ A B (f : C.Hom A B) 205 | → G.first f D.∘ η B D.∘ F.second f ≡ G.second f D.∘ η A D.∘ F.first f 206 | dinatural A B f = z0≡z1 where 207 | 208 | -- Given a factorisation A → X → B, we define the map 209 | -- F B A → F X X → G X X → G A B 210 | -- which interpolates between the two sides of the dinaturality hexagon. 211 | z : Factorisation C A B → D.Hom (F.₀ (B , A)) (G.₀ (A , B)) 212 | z (factor X l r) = G.₁ (l , r) D.∘ η X D.∘ F.₁ (r , l) 213 | 214 | z0≡z1 : z (id∘ f) ≡ z (f ∘id) 215 | z0≡z1 = parametricity (ap-bridge z (factorisation-bridge C-complete C-category f)) 216 | ``` 217 | -------------------------------------------------------------------------------- /src-1lab/ErasureOpen.lagda.md: -------------------------------------------------------------------------------- 1 | ```agda 2 | open import 1Lab.Prelude hiding (map) 3 | open import 1Lab.Reflection.Induction 4 | ``` 5 | 6 | Investigating the fact that Agda's erasure modality is an open modality. 7 | Terminology is borrowed and some proofs are extracted from the paper 8 | [Modalities in homotopy type theory](https://arxiv.org/abs/1706.07526) 9 | by Rijke, Shulman and Spitters. 10 | The erasure modality was previously investigated in 11 | [Logical properties of a modality for erasure](https://www.cse.chalmers.se/~nad/publications/danielsson-erased.pdf) 12 | by Danielsson. 13 | 14 | ```agda 15 | module ErasureOpen where 16 | 17 | private variable 18 | ℓ ℓ' : Level 19 | A B : Type ℓ 20 | ``` 21 | 22 | ## Erasure as an open modality 23 | 24 | The `Erased` monadic modality, internalising `@0`: 25 | 26 | ```agda 27 | record Erased (@0 A : Type ℓ) : Type ℓ where 28 | constructor [_] 29 | field 30 | @0 erased : A 31 | 32 | open Erased 33 | 34 | η : {@0 A : Type ℓ} → A → Erased A 35 | η x = [ x ] 36 | 37 | μ : {@0 A : Type ℓ} → Erased (Erased A) → Erased A 38 | μ [ [ x ] ] = [ x ] 39 | ``` 40 | 41 | ...is equivalent to the **open** modality `○` induced by the following subsingleton: 42 | 43 | ```agda 44 | data Compiling : Type where 45 | @0 compiling : Compiling 46 | 47 | Compiling-is-prop : is-prop Compiling 48 | Compiling-is-prop compiling compiling = refl 49 | 50 | ○_ : Type ℓ → Type ℓ 51 | ○ A = Compiling → A 52 | 53 | ○'_ : ○ Type ℓ → Type ℓ 54 | ○' A = (c : Compiling) → A c 55 | 56 | infix 30 ○_ ○'_ 57 | 58 | ○→Erased : ○ A → Erased A 59 | ○→Erased a .erased = a compiling 60 | 61 | -- Agda considers clauses that match on erased constructors as erased. 62 | Erased→○ : Erased A → ○ A 63 | Erased→○ a compiling = a .erased 64 | 65 | ○≃Erased : ○ A ≃ Erased A 66 | ○≃Erased = Iso→Equiv (○→Erased , 67 | iso Erased→○ (λ _ → refl) (λ _ → funext λ where compiling → refl)) 68 | 69 | η○ : A → ○ A 70 | η○ a _ = a 71 | ``` 72 | 73 | Since Agda allows erased matches for the empty type, the empty type is 74 | modal; in other words, we are not not `Compiling`. 75 | 76 | ```agda 77 | ¬¬compiling : ¬ ¬ Compiling 78 | ¬¬compiling ¬c with ○→Erased ¬c 79 | ... | () 80 | ``` 81 | 82 | ## Open and closed modalities 83 | 84 | The corresponding **closed** modality `●` is given by the join with `Compiling`, 85 | which is equivalent to the following higher inductive type. 86 | 87 | ```agda 88 | data ●_ (A : Type ℓ) : Type ℓ where 89 | -- At runtime, we only have A. 90 | η● : A → ● A 91 | -- At compile time, we also have an erased "cone" that glues all of A together, 92 | -- so that ● A is contractible. 93 | @0 tip : ● A 94 | @0 cone : (a : A) → η● a ≡ tip 95 | 96 | infix 30 ●_ 97 | 98 | unquoteDecl ●-elim = make-elim ●-elim (quote ●_) 99 | 100 | @0 ●-contr : is-contr (● A) 101 | ●-contr {A = A} = contr tip λ a → sym (ps a) where 102 | ps : (a : ● A) → a ≡ tip 103 | ps = ●-elim cone refl λ a i j → cone a (i ∨ j) 104 | ``` 105 | 106 | The rest of this file investigates some properties of open and closed 107 | modalities that are not specific to the `Compiling` proposition we use here. 108 | 109 |
110 | Some common definitions about higher modalities 111 | 112 | ```agda 113 | module Modality 114 | {○_ : ∀ {ℓ} → Type ℓ → Type ℓ} 115 | (η○ : ∀ {ℓ} {A : Type ℓ} → A → ○ A) 116 | (○-elim : ∀ {ℓ ℓ'} {A : Type ℓ} {P : ○ A → Type ℓ'} 117 | → ((a : A) → ○ P (η○ a)) → (a : ○ A) → ○ P a) 118 | (○-elim-β : ∀ {ℓ ℓ'} {A : Type ℓ} {P : ○ A → Type ℓ'} {pη : (a : A) → ○ P (η○ a)} 119 | → (a : A) → ○-elim {P = P} pη (η○ a) ≡ pη a) 120 | (○-≡-modal : ∀ {ℓ} {A : Type ℓ} {x y : ○ A} → is-equiv (η○ {A = x ≡ y})) 121 | where 122 | 123 | modal : Type ℓ → Type ℓ 124 | modal A = is-equiv (η○ {A = A}) 125 | 126 | modal-map : (A → B) → Type _ 127 | modal-map {B = B} f = (b : B) → modal (fibre f b) 128 | 129 | connected : Type ℓ → Type ℓ 130 | connected A = is-contr (○ A) 131 | 132 | connected-map : (A → B) → Type _ 133 | connected-map {B = B} f = (b : B) → connected (fibre f b) 134 | 135 | modal+connected→contr : modal A → connected A → is-contr A 136 | modal+connected→contr A-mod A-conn = Equiv→is-hlevel 0 (η○ , A-mod) A-conn 137 | 138 | modal+connected→equiv : {f : A → B} → modal-map f → connected-map f → is-equiv f 139 | modal+connected→equiv f-mod f-conn .is-eqv b = modal+connected→contr (f-mod b) (f-conn b) 140 | 141 | elim-modal 142 | : ∀ {ℓ ℓ'} {A : Type ℓ} {P : ○ A → Type ℓ'} 143 | → (∀ a → modal (P a)) 144 | → ((a : A) → P (η○ a)) → (a : ○ A) → P a 145 | elim-modal P-modal pη a = equiv→inverse (P-modal a) (○-elim (λ a → η○ (pη a)) a) 146 | 147 | elim-modal-β 148 | : ∀ {ℓ ℓ'} {A : Type ℓ} {P : ○ A → Type ℓ'} P-modal {pη : (a : A) → P (η○ a)} 149 | → (a : A) → elim-modal {P = P} P-modal pη (η○ a) ≡ pη a 150 | elim-modal-β P-modal {pη} a = 151 | ap (equiv→inverse (P-modal (η○ a))) (○-elim-β a) 152 | ∙ equiv→unit (P-modal (η○ a)) (pη a) 153 | 154 | map : (A → B) → ○ A → ○ B 155 | map f = ○-elim (η○ ∘ f) 156 | 157 | map-≃ : A ≃ B → (○ A) ≃ (○ B) 158 | map-≃ e = map (e .fst) , is-iso→is-equiv λ where 159 | .is-iso.from → map (Equiv.from e) 160 | .is-iso.rinv → elim-modal (λ _ → ○-≡-modal) λ b → 161 | ap (map (e .fst)) (○-elim-β b) ∙ ○-elim-β (Equiv.from e b) ∙ ap η○ (Equiv.ε e b) 162 | .is-iso.linv → elim-modal (λ _ → ○-≡-modal) λ a → 163 | ap (map (Equiv.from e)) (○-elim-β a) ∙ ○-elim-β (e .fst a) ∙ ap η○ (Equiv.η e a) 164 | 165 | retract-○→modal : (η⁻¹ : ○ A → A) → is-left-inverse η⁻¹ η○ → modal A 166 | retract-○→modal η⁻¹ ret = is-iso→is-equiv $ 167 | iso η⁻¹ (elim-modal (λ _ → ○-≡-modal) λ a → ap η○ (ret a)) ret 168 | 169 | retract→modal 170 | : (f : A → B) (g : B → A) 171 | → is-left-inverse f g → modal A → modal B 172 | retract→modal {B = B} f g ret A-modal = retract-○→modal η⁻¹ linv where 173 | η⁻¹ : ○ B → B 174 | η⁻¹ = f ∘ elim-modal (λ _ → A-modal) g 175 | linv : is-left-inverse η⁻¹ η○ 176 | linv b = ap f (elim-modal-β (λ _ → A-modal) b) ∙ ret b 177 | 178 | modal-≃ : B ≃ A → modal A → modal B 179 | modal-≃ e = retract→modal (Equiv.from e) (Equiv.to e) (Equiv.η e) 180 | 181 | connected-≃ : B ≃ A → connected A → connected B 182 | connected-≃ e A-conn = Equiv→is-hlevel 0 (map-≃ e) A-conn 183 | 184 | ≡-modal : modal A → ∀ {x y : A} → modal (x ≡ y) 185 | ≡-modal A-modal = modal-≃ (ap-equiv (η○ , A-modal)) ○-≡-modal 186 | 187 | PathP-modal : {A : I → Type ℓ} → modal (A i0) → ∀ {x y} → modal (PathP A x y) 188 | PathP-modal {A = A} A-modal {x} {y} = subst modal (sym (PathP≡Path⁻ A x y)) (≡-modal A-modal) 189 | 190 | reflection-modal : modal (○ A) 191 | reflection-modal = is-iso→is-equiv λ where 192 | .is-iso.from → ○-elim id 193 | .is-iso.rinv → elim-modal (λ _ → ○-≡-modal) λ a → ap η○ (○-elim-β a) 194 | .is-iso.linv → ○-elim-β 195 | 196 | Π-modal : {B : A → Type ℓ} → (∀ a → modal (B a)) → modal ((a : A) → B a) 197 | Π-modal B-modal = retract-○→modal 198 | (λ f a → elim-modal (λ _ → B-modal _) (_$ a) f) 199 | (λ f → funext λ a → elim-modal-β (λ _ → B-modal _) f) 200 | 201 | Σ-modal : {B : A → Type ℓ} → modal A → (∀ a → modal (B a)) → modal (Σ A B) 202 | Σ-modal {B = B} A-modal B-modal = retract-○→modal 203 | (Equiv.from Σ-Π-distrib 204 | ( elim-modal (λ _ → A-modal) fst 205 | , elim-modal (λ _ → B-modal _) λ (a , b) → 206 | subst B (sym (elim-modal-β (λ _ → A-modal) (a , b))) b)) 207 | λ (a , b) → 208 | elim-modal-β (λ _ → A-modal) (a , b) 209 | ,ₚ elim-modal-β (λ _ → B-modal _) (a , b) ◁ to-pathp⁻ refl 210 | 211 | η-connected : connected-map (η○ {A = A}) 212 | η-connected a = contr 213 | (○-elim {P = fibre η○} (λ a → η○ (a , refl)) a) 214 | (elim-modal (λ _ → ○-≡-modal) λ (a' , p) → 215 | J (λ a p → ○-elim (λ x → η○ (x , refl)) a ≡ η○ (a' , p)) (○-elim-β a') p) 216 | 217 | ○Σ○≃○Σ : {B : A → Type ℓ} → (○ (Σ A λ a → ○ B a)) ≃ (○ (Σ A B)) 218 | ○Σ○≃○Σ .fst = ○-elim λ (a , b) → map (a ,_) b 219 | ○Σ○≃○Σ .snd = is-iso→is-equiv λ where 220 | .is-iso.from → map (Σ-map₂ η○) 221 | .is-iso.rinv → elim-modal (λ _ → ○-≡-modal) λ (a , b) → 222 | ap (○-elim _) (○-elim-β (a , b)) ∙ ○-elim-β (a , η○ b) ∙ ○-elim-β b 223 | .is-iso.linv → elim-modal (λ _ → ○-≡-modal) λ (a , b) → 224 | ap (map _) (○-elim-β (a , b)) ∙ elim-modal 225 | {P = λ b → ○-elim _ (○-elim _ b) ≡ η○ (a , b)} (λ _ → ○-≡-modal) 226 | (λ b → ap (○-elim _) (○-elim-β b) ∙ ○-elim-β (a , b)) b 227 | 228 | Σ-connected : {B : A → Type ℓ} → connected A → (∀ a → connected (B a)) → connected (Σ A B) 229 | Σ-connected A-conn B-conn = Equiv→is-hlevel 0 (○Σ○≃○Σ e⁻¹) 230 | (connected-≃ (Σ-contract B-conn) A-conn) 231 | 232 | -- Additional properties of *lex* modalities 233 | 234 | module _ (○-lex : ∀ {ℓ} {A : Type ℓ} {a b : A} → (○ (a ≡ b)) ≃ (η○ a ≡ η○ b)) where 235 | ≡-connected : connected A → {x y : A} → connected (x ≡ y) 236 | ≡-connected A-conn = Equiv→is-hlevel 0 ○-lex (Path-is-hlevel 0 A-conn) 237 | 238 | PathP-connected : {A : I → Type ℓ} → connected (A i0) → ∀ {x y} → connected (PathP A x y) 239 | PathP-connected {A = A} A-conn {x} {y} = 240 | subst connected (sym (PathP≡Path⁻ A x y)) (≡-connected A-conn) 241 | ``` 242 |
243 | 244 | `○` and `●` are higher modalities, so we can instantiate this module 245 | for both of them. 246 | 247 | ```agda 248 | ○-elim-○ 249 | : ∀ {ℓ ℓ'} {A : Type ℓ} {P : ○ A → Type ℓ'} 250 | → ((a : A) → ○ P (η○ a)) → (a : ○ A) → ○ P a 251 | ○-elim-○ {P = P} pη a c = 252 | subst P (funext λ _ → ap a (Compiling-is-prop _ _)) (pη (a c) c) 253 | 254 | ○-≡-modal : {x y : ○ A} → is-equiv (η○ {A = x ≡ y}) 255 | ○-≡-modal = is-iso→is-equiv λ where 256 | .is-iso.from p i compiling → p compiling i compiling 257 | .is-iso.rinv p i compiling j compiling → p compiling j compiling 258 | .is-iso.linv p i j compiling → p j compiling 259 | 260 | ●-elim-● 261 | : ∀ {ℓ ℓ'} {A : Type ℓ} {P : ● A → Type ℓ'} 262 | → ((a : A) → ● P (η● a)) → (a : ● A) → ● P a 263 | ●-elim-● pη = ●-elim pη tip λ _ → is-contr→pathp (λ _ → ●-contr) _ _ 264 | 265 | ●-≡-modal : {x y : ● A} → is-equiv (η● {A = x ≡ y}) 266 | ●-≡-modal = is-iso→is-equiv λ where 267 | .is-iso.from → ●-elim id (is-contr→is-prop ●-contr _ _) 268 | λ p → is-contr→is-set ●-contr _ _ _ _ 269 | .is-iso.rinv → ●-elim (λ _ → refl) (sym (●-contr .paths _)) 270 | λ p → is-set→squarep (λ _ _ → is-contr→is-set ●-contr) _ _ _ _ 271 | .is-iso.linv _ → refl 272 | 273 | module ○ = Modality η○ ○-elim-○ (λ _ → funext λ _ → transport-refl _) ○-≡-modal 274 | module ● = Modality η● ●-elim-● (λ _ → refl) ●-≡-modal 275 | ``` 276 | 277 | Open and closed modalities are lex. 278 | 279 | ```agda 280 | ○-lex : {a b : A} → ○ (a ≡ b) ≃ (η○ a ≡ η○ b) 281 | ○-lex = funext≃ 282 | 283 | module ●-ids {A : Type ℓ} {a : A} where 284 | code : ● A → Type ℓ 285 | code = ●-elim (λ b → ● (a ≡ b)) (Lift _ ⊤) (λ b → ua (is-contr→≃ ●-contr (hlevel 0))) 286 | 287 | code-refl : code (η● a) 288 | code-refl = η● refl 289 | 290 | decode : ∀ b → code b → η● a ≡ b 291 | decode = ●.elim-modal (λ _ → ●.Π-modal λ _ → ●-≡-modal) 292 | λ a → ●.elim-modal (λ _ → ●-≡-modal) (ap η●) 293 | 294 | decode-over : ∀ b (c : code b) → PathP (λ i → code (decode b c i)) code-refl c 295 | decode-over = ●.elim-modal (λ _ → ●.Π-modal λ _ → ●.PathP-modal ●.reflection-modal) 296 | λ a → ●.elim-modal (λ _ → ●.PathP-modal ●.reflection-modal) 297 | λ p i → η● λ j → p (i ∧ j) 298 | 299 | ids : is-based-identity-system (η● a) code code-refl 300 | ids .to-path {b} = decode b 301 | ids .to-path-over {b} = decode-over b 302 | 303 | ●-lex : {a b : A} → ● (a ≡ b) ≃ (η● a ≡ η● b) 304 | ●-lex = based-identity-system-gives-path ●-ids.ids 305 | ``` 306 | 307 | Some equivalences specific to open and closed modalities: 308 | 309 |
310 | `●-modal A ≃ ○ (is-contr A) ≃ is-contr (○ A) = ○-connected A` 311 |
312 | 313 | ```agda 314 | @0 ●-modal→contr : ●.modal A → is-contr A 315 | ●-modal→contr A-modal = Equiv→is-hlevel 0 (η● , A-modal) ●-contr 316 | 317 | contr→●-modal : @0 is-contr A → ●.modal A 318 | contr→●-modal A-contr = ●.retract-○→modal 319 | (●-elim id (A-contr .centre) λ a → sym (A-contr .paths a)) 320 | λ _ → refl 321 | 322 | contr→○-connected : @0 is-contr A → ○.connected A 323 | contr→○-connected A-contr = contr (Erased→○ [ A-contr .centre ]) λ a → 324 | funext λ where compiling → A-contr .paths _ 325 | 326 | @0 ○-connected→contr : ○.connected A → is-contr A 327 | ○-connected→contr A-conn = contr (A-conn .centre compiling) λ a → 328 | A-conn .paths (η○ a) $ₚ compiling 329 | 330 | ○-connected→●-modal : ○.connected A → ●.modal A 331 | ○-connected→●-modal A-conn = contr→●-modal (○-connected→contr A-conn) 332 | ``` 333 | 334 | ## Artin gluing 335 | 336 | We prove an **Artin gluing** theorem: every type `A` is equivalent to a 337 | certain pullback of `○ A` and `● A` over `● ○ A`, which we call `Fracture A`. 338 | Handwaving, this corresponds to decomposing a type into its "compile time" 339 | part and its "runtime" part. 340 | 341 | ```agda 342 | ○→●○ : ○ A → ● ○ A 343 | ○→●○ = η● 344 | 345 | ●→●○ : ● A → ● ○ A 346 | ●→●○ = ●.map η○ 347 | 348 | Fracture : Type ℓ → Type ℓ 349 | Fracture A = Σ (○ A × ● A) λ (o , c) → ○→●○ o ≡ ●→●○ c 350 | 351 | module _ {A : Type ℓ} where 352 | fracture : A → Fracture A 353 | fracture a = (η○ a , η● a) , refl 354 | ``` 355 | 356 | The idea is to prove that the fibres of the `fracture` map are both 357 | `●`-modal and `●`-connected, and hence contractible. 358 | 359 | For the modal part, we observe that an element of the fibre of `fracture` 360 | at a triple `(o : ○ A, c : ● A, p)` can be rearranged into an element 361 | of the fibre of `η○` at `o` (which is `○`-connected, hence `●`-modal) together with 362 | a dependent path whose type is `●`-modal by standard results about higher modalities. 363 | 364 | ```agda 365 | fracture-modal : ●.modal-map fracture 366 | fracture-modal ((o , c) , p) = ●.modal-≃ e $ 367 | ●.Σ-modal (○-connected→●-modal (○.η-connected _)) λ _ → 368 | ●.PathP-modal $ ●.Σ-modal ●.reflection-modal λ _ → ●-≡-modal 369 | where 370 | e : fibre fracture ((o , c) , p) 371 | ≃ Σ (fibre η○ o) λ (a , q) → 372 | PathP (λ i → Σ (● A) λ c → ○→●○ (q i) ≡ ●→●○ c) (η● a , refl) (c , p) 373 | e = Σ-ap-snd (λ _ → ap-equiv (Σ-assoc e⁻¹) ∙e Σ-pathp≃ e⁻¹) ∙e Σ-assoc 374 | ``` 375 | 376 | Almost symmetrically, for the connected part, we rearrange the fibre 377 | into an element of the fibre of `η●` at `c` (which is `●`-connected) together 378 | with a dependent path in the fibres of `○→●○`. Since the latter is 379 | defined as `η●` its fibres are `●`-connected as well, hence the path type 380 | is `●`-connected because `●` is lex. 381 | 382 | ```agda 383 | fracture-connected : ●.connected-map fracture 384 | fracture-connected ((o , c) , p) = ●.connected-≃ e $ 385 | ●.Σ-connected (●.η-connected _) λ _ → 386 | ●.PathP-connected ●-lex (●.η-connected _) 387 | where 388 | e : fibre fracture ((o , c) , p) 389 | ≃ Σ (fibre η● c) λ (a , q) → 390 | PathP (λ i → Σ (○ A) λ o → ○→●○ o ≡ ●→●○ (q i)) (η○ a , refl) (o , p) 391 | e = Σ-ap-snd (λ _ → ap-equiv (Σ-ap-fst ×-swap ∙e Σ-assoc e⁻¹) ∙e Σ-pathp≃ e⁻¹) ∙e Σ-assoc 392 | 393 | fracture-is-equiv : is-equiv fracture 394 | fracture-is-equiv = ●.modal+connected→equiv fracture-modal fracture-connected 395 | 396 | Artin-gluing : A ≃ Fracture A 397 | Artin-gluing = fracture , fracture-is-equiv 398 | ``` 399 | -------------------------------------------------------------------------------- /src-1lab/FirstGroupCohomology.agda: -------------------------------------------------------------------------------- 1 | open import 1Lab.Path.Reasoning 2 | open import 1Lab.Prelude 3 | 4 | open import Algebra.Group.Cat.Base 5 | open import Algebra.Group.Concrete 6 | open import Algebra.Group.Ab 7 | 8 | open import Cat.Prelude 9 | 10 | open import Homotopy.Space.Delooping 11 | 12 | -- This now lives at https://1lab.dev/Algebra.Group.Concrete.Abelian.html#first-abelian-group-cohomology 13 | module FirstGroupCohomology where 14 | 15 | open Precategory 16 | 17 | π₁BG≡G : ∀ {ℓ} (G : Group ℓ) → π₁B (Concrete G) ≡ G 18 | π₁BG≡G G = π₁B≡π₀₊₁ (Concrete G) ∙ sym (G≡π₁B G) 19 | 20 | -- Any two loops commute in the delooping of an abelian group. 21 | ab→square : ∀ {ℓ} {H : Group ℓ} (H-ab : is-commutative-group H) 22 | → {x : Deloop H} (p q : x ≡ x) → Square p q q p 23 | ab→square {H = H} H-ab {x} = Deloop-elim-prop H (λ x → (p q : x ≡ x) → Square p q q p) (λ _ → hlevel 1) 24 | (λ p q → commutes→square (subst is-commutative-group (sym (π₁BG≡G H)) H-ab p q)) x 25 | 26 | module _ {ℓ} (G : Group ℓ) (H : Group ℓ) (H-ab : is-commutative-group H) where 27 | -- The first cohomology of G with coefficients in H. 28 | -- We will show that it is equivalent to the set of group homomorphisms from G 29 | -- to H, assuming that H is abelian. 30 | H¹[G,H] = ∥ (Deloop G → Deloop H) ∥₀ 31 | 32 | unpoint : (Deloop∙ G →∙ Deloop∙ H) → H¹[G,H] 33 | unpoint (f , _) = inc f 34 | 35 | work : ∀ f → f base ≡ base → is-contr (fibre unpoint (inc f)) 36 | work f ptf .centre = (f , ptf) , refl 37 | work f ptf .paths ((g , ptg) , g≡f) = Σ-prop-path! (Σ-pathp 38 | (funext (Deloop-elim-set G _ (λ _ → hlevel 2) (ptf ∙ sym ptg) λ z → rec! 39 | (λ g≡f → J 40 | (λ g _ → ∀ ptg → Square (ap f (path z)) (ptf ∙ sym ptg) (ptf ∙ sym ptg) (ap g (path z))) 41 | (λ _ → ab→square H-ab _ _) 42 | (sym g≡f) ptg) 43 | (∥-∥₀-path.to g≡f))) 44 | (flip₂ (∙-filler'' ptf (sym ptg)))) 45 | 46 | unpoint-is-equiv : is-equiv unpoint 47 | unpoint-is-equiv .is-eqv = ∥-∥₀-elim (λ _ → hlevel 2) 48 | λ f → rec! (work f) (Deloop-is-connected (f base)) 49 | 50 | unpoint≃ : H¹[G,H] ≃ (Deloop∙ G →∙ Deloop∙ H) 51 | unpoint≃ = (unpoint , unpoint-is-equiv) e⁻¹ 52 | 53 | delooping : (Deloop∙ G →∙ Deloop∙ H) ≃ Hom (Groups ℓ) (π₁B (Concrete G)) (π₁B (Concrete H)) 54 | delooping = _ , π₁F-is-ff {_} {Concrete G} {Concrete H} 55 | 56 | first-group-cohomology : H¹[G,H] ≃ Hom (Groups ℓ) G H 57 | first-group-cohomology = unpoint≃ ∙e delooping 58 | ∙e path→equiv (ap₂ (Hom (Groups ℓ)) (π₁BG≡G G) (π₁BG≡G H)) 59 | 60 | -- As a cool application, the space of endomorphisms of the delooping of ℤ/2ℤ has 61 | -- exactly two connected components! 62 | -- (But note that there is no type with exactly two endomorphisms: it would be a set, 63 | -- and nⁿ = 2 has no integer solutions.) 64 | -------------------------------------------------------------------------------- /src-1lab/Goat.agda: -------------------------------------------------------------------------------- 1 | open import 1Lab.Prelude 2 | open import Data.Dec 3 | open import Data.Nat 4 | 5 | {- 6 | A formalisation of https://en.wikipedia.org/wiki/Wolf,_goat_and_cabbage_problem 7 | to demonstrate proof by reflection. 8 | -} 9 | module Goat where 10 | 11 | holds : ∀ {ℓ} (A : Type ℓ) ⦃ _ : Dec A ⦄ → Type 12 | holds _ ⦃ yes _ ⦄ = ⊤ 13 | holds _ ⦃ no _ ⦄ = ⊥ 14 | 15 | data Side : Type where 16 | left right : Side 17 | 18 | left≠right : ¬ left ≡ right 19 | left≠right p = subst (λ { left → ⊤; right → ⊥ }) p tt 20 | 21 | instance 22 | Discrete-Side : Discrete Side 23 | Discrete-Side {left} {left} = yes refl 24 | Discrete-Side {left} {right} = no left≠right 25 | Discrete-Side {right} {left} = no (left≠right ∘ sym) 26 | Discrete-Side {right} {right} = yes refl 27 | 28 | cross : Side → Side 29 | cross left = right 30 | cross right = left 31 | 32 | record State : Type where 33 | constructor state 34 | field 35 | farmer wolf goat cabbage : Side 36 | 37 | open State 38 | 39 | count-left : Side → Nat 40 | count-left left = 1 41 | count-left right = 0 42 | count-lefts : State → Nat 43 | count-lefts (state f w g c) = count-left f + count-left w + count-left g + count-left c 44 | 45 | is-valid : State → Type 46 | is-valid s@(state f w g c) = count-lefts s ≡ 2 → f ≡ g 47 | 48 | record Valid-state : Type where 49 | constructor valid 50 | field 51 | has-state : State 52 | ⦃ has-valid ⦄ : holds (is-valid has-state) 53 | 54 | open Valid-state 55 | 56 | data Move : State → State → Type where 57 | go-alone : ∀ {s} → Move s (record s { farmer = cross (s .farmer) }) 58 | take-wolf : ∀ {s} → Move s (record s { farmer = cross (s .farmer); wolf = cross (s .wolf) }) 59 | take-goat : ∀ {s} → Move s (record s { farmer = cross (s .farmer); goat = cross (s .goat) }) 60 | take-cabbage : ∀ {s} → Move s (record s { farmer = cross (s .farmer); cabbage = cross (s .cabbage) }) 61 | 62 | data Moves : Valid-state → Valid-state → Type where 63 | done : ∀ {s} → Moves s s 64 | _∷_ : ∀ {a b c} ⦃ _ : holds (is-valid b) ⦄ → Move (a .has-state) b → Moves (valid b) c → Moves a c 65 | 66 | infixr 6 _∷_ 67 | 68 | initial final : Valid-state 69 | initial = valid (state left left left left) 70 | final = valid (state right right right right) 71 | 72 | goal : Moves initial final 73 | goal = take-goat ∷ go-alone ∷ take-wolf ∷ take-goat ∷ take-cabbage ∷ go-alone ∷ take-goat ∷ done 74 | -- goal = {! take-wolf ∷ ? !} -- No instance of type holds (is-valid ...) was found in scope. 75 | -------------------------------------------------------------------------------- /src-1lab/Hats.agda: -------------------------------------------------------------------------------- 1 | open import 1Lab.Path.Reasoning 2 | open import 1Lab.Prelude 3 | 4 | open import Algebra.Monoid.Category 5 | open import Algebra.Group 6 | 7 | open import Data.List hiding (lookup) 8 | open import Data.Fin 9 | open import Data.Fin.Closure 10 | 11 | open is-iso 12 | 13 | {- 14 | This is a formalisation of a hat puzzle whose statement you can read at any 15 | of these places: 16 | 17 | https://www.jsoftware.com/pipermail/general/2007-June/030272.html 18 | https://www.cut-the-knot.org/blue/PuzzleWithHats.shtml 19 | https://twitter.com/gro_tsen/status/1618989823100096512 20 | 21 | 🎩 SPOILERS AHEAD! 🎩 22 | -} 23 | module Hats where 24 | 25 | -- We assume there's at least one person, and that everyone has a unique 26 | -- "name" between 0 and n - 1, known to everyone else. 27 | module _ (n-1 : Nat) where 28 | private 29 | n = suc n-1 30 | Person = Fin n 31 | Hat = Fin n 32 | Hats = Person → Hat 33 | 34 | record Strategy : Type where 35 | -- `guess i xs` is the guess made by the ith person upon seeing the n - 1 36 | -- other hats given by `xs` (a vector of numbers from 0 to n - 1). 37 | field 38 | guess : Person → (Fin n-1 → Hat) → Hat 39 | 40 | -- The relation `hats ✓ i` means that the ith person guesses correctly, 41 | -- given the assignment `hats`. 42 | _✓_ : Hats → Person → Type 43 | hats ✓ i = guess i (delete hats i) ≡ hats i 44 | 45 | -- We are interested in strategies where at least one person guesses 46 | -- correctly for every assignment of hats. 47 | field 48 | one-right : ∀ hats → Σ Person λ i → hats ✓ i 49 | 50 | -- First, note that, given this requirement, there can be at *most* one 51 | -- correct guess for every assignment of hats. 52 | -- This follows from a probabilistic argument: every person guesses correctly 53 | -- with probability 1/n, so the total number of correct guesses across all 54 | -- hat assignments is nⁿ. 55 | -- In order to conclude, we use the fact that any surjection between finite 56 | -- sets of equal cardinality is an equivalence. 57 | exactly-one-right : ∀ hats → is-contr (Σ Person λ i → hats ✓ i) 58 | exactly-one-right hats = Equiv→is-hlevel 0 (Fibre-equiv _ hats e⁻¹) (p-is-equiv .is-eqv hats) 59 | where 60 | probability : ∀ i → Iso (Σ Hats (_✓ i)) (Fin n-1 → Hat) 61 | probability i .fst (hats , _) = delete hats i 62 | probability i .snd .from other .fst = other [ i ≔ guess i other ] 63 | probability i .snd .from other .snd = 64 | guess i ⌜ delete (other [ i ≔ guess i other ]) i ⌝ ≡⟨ ap! (funext (delete-insert _ i _)) ⟩ 65 | guess i other ≡˘⟨ insert-lookup _ i _ ⟩ 66 | (other [ i ≔ guess i other ]) i ∎ 67 | probability i .snd .rinv _ = funext (delete-insert _ i _) 68 | probability i .snd .linv (hats , r) = Σ-prop-path! (funext (insert-delete _ i _ (sym r))) 69 | 70 | only-one : Σ Hats (λ hats → Σ Person (hats ✓_)) ≃ Hats 71 | only-one = 72 | Σ _ (λ hats → Σ _ λ i → hats ✓ i) ≃⟨ Σ-swap₂ ⟩ 73 | Σ _ (λ i → Σ _ λ hats → hats ✓ i) ≃⟨ Σ-ap-snd (Iso→Equiv ∘ probability) ⟩ 74 | Fin n × (Fin n-1 → Fin n) ≃˘⟨ Fin-suc-Π ⟩ 75 | (Fin n → Fin n) ≃∎ 76 | 77 | p : Σ Hats (λ hats → Σ Person (hats ✓_)) → Hats 78 | p = fst 79 | p-is-equiv : is-equiv p 80 | p-is-equiv = Finite-surjection→equiv (inc only-one) p 81 | λ other → inc ((other , one-right other) , refl) 82 | 83 | open Strategy public 84 | 85 | -- n-hypercubes of order m. We won't use the extra degree of generality, 86 | -- but it doesn't hurt. 87 | Hypercube : Nat → Type 88 | Hypercube m = (Fin n → Fin m) → Fin m 89 | 90 | -- Latin hypercubes, or n-ary quasigroups. 91 | -- Every number appears exactly once on each "line"; equivalently, 92 | -- every partial application to n - 1 coordinates is an automorphism. 93 | is-latin : ∀ {m} → Hypercube m → Type 94 | is-latin {m} h = ∀ (i : Fin n) (xs : Fin n-1 → Fin m) → is-equiv λ x → h (xs [ i ≔ x ]) 95 | 96 | Latin-hypercube : Nat → Type 97 | Latin-hypercube m = Σ (Hypercube m) is-latin 98 | 99 | -- Every latin n-hypercube h of order n induces a strategy where everyone 100 | -- guesses that the multiplication of all the hats is equal to their index. 101 | latin→strategy : Latin-hypercube n → Strategy 102 | latin→strategy (h , lat) .guess i other = equiv→inverse (lat i other) i 103 | latin→strategy (h , lat) .one-right hats = 104 | h hats , Equiv.from (eqv (h hats)) refl 105 | where 106 | module L i = Equiv (_ , lat i (delete hats i)) 107 | eqv : ∀ (i : Fin n) → (L.from i i ≡ hats i) ≃ (h hats ≡ i) 108 | eqv i = 109 | L.from i i ≡ hats i ≃⟨ Equiv.adjunct (L.inverse i) ⟩ 110 | i ≡ L.to i (hats i) ≃⟨ sym-equiv ⟩ 111 | L.to i (hats i) ≡ i ≃⟨ ∙-pre-equiv (sym (ap h (funext (insert-delete hats i _ refl)))) ⟩ 112 | h hats ≡ i ≃∎ 113 | 114 | -- In particular, every group structure on Fin n induces a strategy since 115 | -- group multiplication is an n-ary equivalence. 116 | group→latin : Group-on (Fin n) → Latin-hypercube n 117 | group→latin G = mul , mul-equiv 118 | where 119 | open Group-on G hiding (magma-hlevel) 120 | 121 | mul : ∀ {m} → (Fin m → Fin n) → Fin n 122 | mul xs = fold underlying-monoid (tabulate xs) 123 | 124 | mul-equiv : ∀ {m} (i : Fin (suc m)) (xs : Fin m → Fin n) 125 | → is-equiv (λ x → mul (xs [ i ≔ x ])) 126 | mul-equiv i xs with fin-view i 127 | mul-equiv _ xs | zero = ⋆-equivr _ 128 | mul-equiv {suc m} _ xs | suc i = ∘-is-equiv (mul-equiv i (xs ∘ fsuc)) (⋆-equivl _) 129 | 130 | group→strategy : Group-on (Fin n) → Strategy 131 | group→strategy = latin→strategy ∘ group→latin 132 | -------------------------------------------------------------------------------- /src-1lab/Madeleine.agda: -------------------------------------------------------------------------------- 1 | open import 1Lab.Prelude 2 | open import 1Lab.Classical 3 | open import Data.Sum 4 | open import Data.Dec 5 | open import Data.Bool 6 | open import Meta.Invariant 7 | 8 | module Madeleine where 9 | 10 | axiom = ∀ {ℓ} {P Q : Type ℓ} ⦃ _ : H-Level P 1 ⦄ ⦃ _ : H-Level Q 1 ⦄ → ∥ P ⊎ Q ∥ → P ⊎ Q 11 | 12 | lem→axiom : LEM → axiom 13 | lem→axiom lem {P = P} {Q} pq with lem (elΩ P) 14 | ... | yes a = inl (□-out! a) 15 | ... | no ¬a = inr (rec! (λ { (inl p) → absurd (¬a (inc p)); (inr q) → q }) pq) 16 | 17 | module _ (ε : axiom) where 18 | 19 | module _ {ℓ} {X : Type ℓ} ⦃ _ : H-Level X 2 ⦄ (a₀ a₁ : X) where 20 | E : X → Type _ 21 | E x = (a₀ ≡ x) ⊎ (a₁ ≡ x) 22 | 23 | E' : Type _ 24 | E' = Σ X λ x → ∥ E x ∥ 25 | 26 | r : Bool → E' 27 | r true = a₀ , inc (inl refl) 28 | r false = a₁ , inc (inr refl) 29 | 30 | s : E' → Bool 31 | s (x , e) with ε e 32 | ... | inl _ = true 33 | ... | inr _ = false 34 | 35 | r-s : ∀ e → r (s e) ≡ e 36 | r-s (x , e) with ε e 37 | ... | inl p = Σ-prop-path! p 38 | ... | inr p = Σ-prop-path! p 39 | 40 | discrete : Dec (a₀ ≡ a₁) 41 | discrete = invmap 42 | (λ p → ap fst (right-inverse→injective r r-s p)) 43 | (λ p → ap s (Σ-prop-path! p)) 44 | (s (r true) ≡? s (r false)) 45 | 46 | lem : LEM 47 | lem P = invmap (λ p → subst ∣_∣ (sym p) _) (λ p → Ω-ua _ (λ _ → p)) 48 | (discrete P ⊤Ω) 49 | -------------------------------------------------------------------------------- /src-1lab/MonoidalFibres.agda: -------------------------------------------------------------------------------- 1 | open import 1Lab.Prelude 2 | open import Homotopy.Connectedness 3 | open import Cat.Prelude 4 | open import Cat.Functor.Base 5 | open import Cat.Functor.Properties 6 | 7 | -- eso + full-on-isos functors have monoidal fibres. 8 | module MonoidalFibres where 9 | 10 | private variable 11 | o ℓ : Level 12 | C D : Precategory o ℓ 13 | 14 | monoidal-fibres 15 | : ∀ {F : Functor C D} 16 | → is-category C → is-category D 17 | → is-eso F → is-full-on-isos F 18 | → ∀ y → is-connected (Essential-fibre F y) 19 | monoidal-fibres {D = D} {F = F} ccat dcat eso full≅ y = 20 | case eso y of λ y′ Fy′≅y → is-connected∙→is-connected {X = _ , y′ , Fy′≅y} λ (x , Fx≅y) → do 21 | (x≅y′ , eq) ← full≅ (Fy′≅y Iso⁻¹ ∘Iso Fx≅y) 22 | pure (Σ-pathp (ccat .to-path x≅y′) 23 | (≅-pathp _ _ (transport (λ i → PathP (λ j → Hom (F-map-path F ccat dcat x≅y′ (~ i) j) y) (Fx≅y .to) (Fy′≅y .to)) 24 | (Hom-pathp-refll-iso (sym (ap from (Iso-swapl (sym eq)))))))) 25 | where open Univalent dcat 26 | -------------------------------------------------------------------------------- /src-1lab/Mystery.agda: -------------------------------------------------------------------------------- 1 | open import 1Lab.Classical 2 | open import 1Lab.Prelude 3 | 4 | open import Data.Dec 5 | 6 | -- A weird constructive principle equivalent to Markov's principle + WLEM + ¬¬-shift 7 | -- https://types.pl/@ncf/112854858302377592 8 | -- https://x.com/ncfavier/status/1817846740944314834 9 | module Mystery where 10 | 11 | TNE : ∀ {ℓ} {P : Type ℓ} → ¬ ¬ ¬ P → ¬ P 12 | TNE h p = h λ k → k p 13 | 14 | case01 : ∀ {ℓ} {A : Type ℓ} → A → A → Nat → A 15 | case01 z s zero = z 16 | case01 z s (suc n) = s 17 | 18 | mystery MP DNS : Type 19 | 20 | mystery = (P : Nat → Ω) → (¬ ∀ n → ∣ P n ∣) → ∃ _ λ n → ¬ ∣ P n ∣ 21 | 22 | MP = (P : Nat → Ω) → (∀ n → Dec ∣ P n ∣) → (¬ ∀ n → ∣ P n ∣) → ∃ _ λ n → ¬ ∣ P n ∣ 23 | 24 | DNS = (P : Nat → Ω) → (∀ n → ¬ ¬ ∣ P n ∣) → ¬ ¬ ∀ n → ∣ P n ∣ 25 | 26 | mystery→MP : mystery → MP 27 | mystery→MP m P _ = m P 28 | 29 | mystery→WLEM : mystery → WLEM 30 | mystery→WLEM m P = case m (case01 P (¬Ω P)) (λ h → h 1 (h 0)) of λ where 31 | zero p → yes p 32 | (suc _) p → no p 33 | 34 | mystery→DNS : mystery → DNS 35 | mystery→DNS m P h k = case m P k of h 36 | 37 | MP+WLEM+DNS→mystery : MP × WLEM × DNS → mystery 38 | MP+WLEM+DNS→mystery (mp , wlem , dns) P h = 39 | mp (λ n → ¬Ω ¬Ω P n) (λ n → wlem (¬Ω P n)) (λ k → dns P k h) 40 | <&> Σ-map id TNE 41 | 42 | mystery≃MP+WLEM+DNS : mystery ≃ (MP × WLEM × DNS) 43 | mystery≃MP+WLEM+DNS = prop-ext! 44 | ⟨ mystery→MP , ⟨ mystery→WLEM , mystery→DNS ⟩ ⟩ 45 | MP+WLEM+DNS→mystery 46 | -------------------------------------------------------------------------------- /src-1lab/Möbius.agda: -------------------------------------------------------------------------------- 1 | open import 1Lab.Prelude 2 | 3 | open import Data.Int renaming (Int to ℤ) 4 | 5 | open import Homotopy.Space.Circle hiding (Cover ; decode) 6 | 7 | -- https://math.stackexchange.com/questions/4940313/giving-calculating-explicit-homomorphism-between-fundamental-groups 8 | module Möbius where 9 | 10 | data Möbius : Type where 11 | up down : Möbius 12 | seam : up ≡ down 13 | top : up ≡ down 14 | bottom : down ≡ up 15 | surf : PathP (λ i → top i ≡ bottom i) seam (sym seam) 16 | 17 | Cover : Möbius → Type 18 | Cover up = ℤ 19 | Cover down = ℤ 20 | Cover (seam i) = ℤ 21 | Cover (top i) = ua suc-equiv i 22 | Cover (bottom i) = ua suc-equiv i 23 | Cover (surf i j) = ua suc-equiv i 24 | 25 | decode : ∀ {x} → up ≡ x → Cover x 26 | decode p = subst Cover p 0 27 | 28 | ι : S¹ → Möbius 29 | ι = S¹-rec up (top ∙ bottom) 30 | 31 | ι* : ℤ → ℤ 32 | ι* = decode ∘ ap ι ∘ loopⁿ 33 | 34 | _ : ι* 1 ≡ 2 35 | _ = refl 36 | -------------------------------------------------------------------------------- /src-1lab/ObjectClassifier.agda: -------------------------------------------------------------------------------- 1 | open import 1Lab.Type 2 | open import 1Lab.Type.Sigma 3 | open import 1Lab.Type.Pointed 4 | open import 1Lab.Path 5 | open import 1Lab.HLevel 6 | open import 1Lab.HLevel.Closure 7 | open import 1Lab.Equiv 8 | 9 | -- Univalence from object classifiers in the sense of higher topos theory. 10 | module ObjectClassifier where 11 | 12 | -- The type of arrows/bundles/fibrations. 13 | Bundle : ∀ ℓ → Type (lsuc ℓ) 14 | Bundle ℓ 15 | = Σ (Type ℓ) λ A 16 | → Σ (Type ℓ) λ B 17 | → A → B 18 | 19 | -- The standard pullback construction (HoTT book 2.15.11). 20 | record Pullback {ℓ ℓ'} {B : Type ℓ} {C D : Type ℓ'} (s : B → D) (q : C → D) : Type (ℓ ⊔ ℓ') where 21 | constructor pb 22 | field 23 | pb₁ : B 24 | pb₂ : C 25 | pbeq : s pb₁ ≡ q pb₂ 26 | 27 | open Pullback 28 | 29 | pb-path : ∀ {ℓ ℓ'} {B : Type ℓ} {C D : Type ℓ'} {s : B → D} {q : C → D} → {a b : Pullback s q} 30 | → (p1 : a .pb₁ ≡ b .pb₁) → (p2 : a .pb₂ ≡ b .pb₂) → PathP (λ i → s (p1 i) ≡ q (p2 i)) (a .pbeq) (b .pbeq) 31 | → a ≡ b 32 | pb-path p1 p2 pe i = pb (p1 i) (p2 i) (pe i) 33 | 34 | -- The morphisms of interest between bundles p : A → B and q : C → D are pairs 35 | -- r : A → C, s : B → D that make a *pullback square*: 36 | -- r 37 | -- A ------> C 38 | -- | ⯾ | 39 | -- p | | q 40 | -- v v 41 | -- B ------> D 42 | -- s 43 | -- Rather than laboriously state the universal property of a pullback, we take it 44 | -- on faith that the construction above has the universal property (this is 45 | -- exercise 2.11 in the HoTT book) and simply define "being a pullback" as having 46 | -- r and p factor through an equivalence A ≃ Pullback s q. 47 | -- This completely determines r by the factorisation r = pb₂ ∘ e .fst, so we can 48 | -- omit it by contractibility of singletons. 49 | _⇒_ : ∀ {ℓ} {ℓ'} → Bundle ℓ → Bundle ℓ' → Type (ℓ ⊔ ℓ') 50 | (A , B , p) ⇒ (C , D , q) 51 | = Σ (B → D) λ s 52 | → Σ (A ≃ Pullback s q) λ e 53 | → p ≡ pb₁ ∘ e .fst 54 | 55 | -- An object classifier is a *universal* bundle U∙ → U such that any other 56 | -- bundle has a unique map (i.e. pullback square) into it. 57 | -- Categorically, it is a terminal object in the category of arrows and pullback squares. 58 | is-classifier : ∀ {ℓ} → Bundle (lsuc ℓ) → Type (lsuc ℓ) 59 | is-classifier {ℓ} u = ∀ (p : Bundle ℓ) → is-contr (p ⇒ u) 60 | 61 | -- The projection from the type of pointed types to the type of types is our 62 | -- universal bundle: the fibre above A : Type ℓ is equivalent to A itself. 63 | Type↓ : ∀ ℓ → Bundle (lsuc ℓ) 64 | Type↓ ℓ = Type∙ ℓ , Type ℓ , fst 65 | 66 | Type↓-fibre : ∀ {ℓ} (A : Type ℓ) → A ≃ Pullback {B = Lift ℓ ⊤} {C = Type∙ ℓ} (λ _ → A) fst 67 | Type↓-fibre A = Iso→Equiv λ where 68 | .fst a → pb _ (A , a) refl 69 | .snd .is-iso.from (pb _ (A' , a) eq) → transport (sym eq) a 70 | .snd .is-iso.linv → transport-refl 71 | .snd .is-iso.rinv (pb _ (A' , a) eq) → pb-path refl (sym (Σ-path (sym eq) refl)) λ i j → eq (i ∧ j) 72 | 73 | postulate 74 | -- We assume that Type↓ is an object classifier in the sense above, and show that 75 | -- this makes it a univalent universe. 76 | Type↓-is-classifier : ∀ {ℓ} → is-classifier (Type↓ ℓ) 77 | 78 | -- Every type is trivially a bundle over the unit type. 79 | ! : ∀ {ℓ} → Type ℓ → Bundle ℓ 80 | ! A = A , Lift _ ⊤ , _ 81 | 82 | -- The key observation is that the type of pullback squares from ! A to Type↓ is 83 | -- equivalent to the type of types equipped with an equivalence to A. 84 | -- Since the former was assumed to be contractible, so is the latter. 85 | lemma : ∀ {ℓ} (A : Type ℓ) → (! A ⇒ Type↓ ℓ) ≃ Σ (Type ℓ) (λ B → A ≃ B) 86 | lemma {ℓ} A = Iso→Equiv λ where 87 | .fst (ty , e , _) → ty _ , e ∙e Type↓-fibre (ty _) e⁻¹ 88 | .snd .is-iso.from (B , e) → (λ _ → B) , e ∙e Type↓-fibre B , refl 89 | .snd .is-iso.linv (ty , e , _) → Σ-pathp refl (Σ-pathp (Σ-prop-path is-equiv-is-prop 90 | (funext λ _ → Equiv.ε (Type↓-fibre (ty _)) _)) refl) 91 | .snd .is-iso.rinv (B , e) → Σ-pathp refl (Σ-prop-path is-equiv-is-prop 92 | (funext λ _ → Equiv.η (Type↓-fibre B) _)) 93 | 94 | -- Equivalences form an identity system, which is another way to state univalence. 95 | univalence : ∀ {ℓ} (A : Type ℓ) → is-contr (Σ (Type ℓ) λ B → A ≃ B) 96 | univalence {ℓ} A = Equiv→is-hlevel 0 (lemma A e⁻¹) (Type↓-is-classifier (! A)) 97 | -------------------------------------------------------------------------------- /src-1lab/PointwiseMonoidal.agda: -------------------------------------------------------------------------------- 1 | open import Cat.Prelude 2 | open import Cat.Functor.Base 3 | open import Cat.Functor.Compose 4 | open import Cat.Functor.Constant 5 | open import Cat.Functor.Equivalence.Path 6 | open import Cat.Monoidal.Base 7 | open import Cat.Monoidal.Diagram.Monoid 8 | open import Cat.Instances.Product 9 | open import Cat.Displayed.Base 10 | open import Cat.Displayed.Total 11 | 12 | open Monoidal-category 13 | open Precategory 14 | open Functor 15 | open _=>_ 16 | 17 | -- ⚠️ WIP ⚠️ 18 | module PointwiseMonoidal 19 | {o o′ ℓ ℓ′} (C : Precategory o ℓ) (D : Precategory o′ ℓ′) 20 | (M : Monoidal-category D) 21 | where 22 | 23 | Pointwise : Monoidal-category Cat[ C , D ] 24 | Pointwise = pw where 25 | prod : Functor (Cat[ C , D ] ×ᶜ Cat[ C , D ]) Cat[ C , D ] 26 | prod .F₀ (a , b) = M .-⊗- F∘ Cat⟨ a , b ⟩ 27 | prod .F₁ {x = x} {y = y} (na , nb) = M .-⊗- ▸ nat where 28 | nat : Cat⟨ x .fst , x .snd ⟩ => Cat⟨ y .fst , y .snd ⟩ 29 | nat .η x = (na .η x) , (nb .η x) 30 | nat .is-natural x y f i = (na .is-natural x y f i) , (nb .is-natural x y f i) 31 | prod .F-id = ext λ _ → M .-⊗- .F-id 32 | prod .F-∘ f g = ext λ _ → M .-⊗- .F-∘ _ _ 33 | pw : Monoidal-category Cat[ C , D ] 34 | pw .-⊗- = prod 35 | pw .Unit = Const (M .Unit) 36 | pw .unitor-l = {! M .unitor-l !} 37 | pw .unitor-r = {! !} 38 | pw .associator = {! !} 39 | pw .triangle = {! !} 40 | pw .pentagon = {! !} 41 | 42 | MonCD→CMonD : Functor (∫ Mon[ Pointwise ]) (Cat[ C , ∫ Mon[ M ] ]) 43 | MonCD→CMonD .F₀ (F , mon) .F₀ c = F .F₀ c , {! !} 44 | MonCD→CMonD .F₀ (F , mon) .F₁ = {! !} 45 | MonCD→CMonD .F₀ (F , mon) .F-id = {! !} 46 | MonCD→CMonD .F₀ (F , mon) .F-∘ = {! !} 47 | MonCD→CMonD .F₁ = {! !} 48 | MonCD→CMonD .F-id = {! !} 49 | MonCD→CMonD .F-∘ = {! !} 50 | 51 | MonCD≡CMonD : ∫ Mon[ Pointwise ] ≡ Cat[ C , ∫ Mon[ M ] ] 52 | MonCD≡CMonD = Precategory-path MonCD→CMonD {! !} 53 | -------------------------------------------------------------------------------- /src-1lab/PostcomposeNotFull.agda: -------------------------------------------------------------------------------- 1 | open import Cat.Instances.Shape.Involution 2 | open import Cat.Instances.Shape.Interval 3 | open import Cat.Functor.Properties 4 | open import Cat.Functor.Compose 5 | open import Cat.Prelude 6 | 7 | open import Data.Bool 8 | 9 | open Precategory 10 | open Functor 11 | open _=>_ 12 | 13 | module PostcomposeNotFull where 14 | 15 | {- 16 | We prove that it is NOT the case that, for every full functor p, the 17 | postcomposition functor p ∘ — is full. 18 | -} 19 | 20 | claim = 21 | ∀ {o ℓ o' ℓ' od ℓd} {C : Precategory o ℓ} {C' : Precategory o' ℓ'} {D : Precategory od ℓd} 22 | → (p : Functor C C') → is-full p → is-full (postcompose p {D = D}) 23 | 24 | module _ (assume : claim) where 25 | {- 26 | The counterexample consists of the following category (identities omitted): 27 | https://q.uiver.app/#q=WzAsMixbMCwwLCJhIl0sWzAsMSwiYiJdLFswLDBdLFsxLDEsIiIsMix7InJhZGl1cyI6LTN9XSxbMCwxLCIiLDAseyJjdXJ2ZSI6LTF9XSxbMCwxLCIiLDEseyJjdXJ2ZSI6MX1dXQ== 28 | where the loops on a and b are involutions, the involution on a swaps 29 | the two morphisms a ⇉ b, and the involution on b leaves them alone. 30 | There is a full functor p from C to the walking arrow that collapses 31 | all the morphisms, and there are two inclusion functors F and G from 32 | the walking involution into C. A natural transformation p ∘ F ⇒ p ∘ G 33 | is trivial, but a natural transformation F ⇒ G is a "ℤ/2ℤ-equivariant" 34 | morphism a → b, that is one that commutes with the involutions on a and b. 35 | There is no such thing in C, hence the action of p ∘ — on natural 36 | transformations (whiskering) cannot be surjective. 37 | -} 38 | 39 | C : Precategory lzero lzero 40 | C .Ob = Bool 41 | C .Hom true true = Bool 42 | C .Hom true false = Bool 43 | C .Hom false true = ⊥ 44 | C .Hom false false = Bool 45 | C .Hom-set true true = hlevel 2 46 | C .Hom-set true false = hlevel 2 47 | C .Hom-set false true = hlevel 2 48 | C .Hom-set false false = hlevel 2 49 | C .id {true} = false 50 | C .id {false} = false 51 | C ._∘_ {true} {true} {true} = xor 52 | C ._∘_ {false} {false} {false} = xor 53 | C ._∘_ {true} {true} {false} f g = xor g f 54 | C ._∘_ {true} {false} {false} f g = g 55 | C .idr {true} {true} f = xor-falser f 56 | C .idr {true} {false} f = refl 57 | C .idr {false} {false} f = xor-falser f 58 | C .idl {true} {true} f = refl 59 | C .idl {true} {false} f = refl 60 | C .idl {false} {false} f = refl 61 | C .assoc {true} {true} {true} {true} f g h = xor-associative f g h 62 | C .assoc {false} {false} {false} {false} f g h = xor-associative f g h 63 | C .assoc {true} {true} {true} {false} f true true = sym (not-involutive f) 64 | C .assoc {true} {true} {true} {false} f true false = refl 65 | C .assoc {true} {true} {true} {false} f false h = refl 66 | C .assoc {true} {true} {false} {false} f g h = refl 67 | C .assoc {true} {false} {false} {false} f g h = refl 68 | 69 | p : Functor C (0≤1 ^op) 70 | p .F₀ o = o 71 | p .F₁ {true} {true} = _ 72 | p .F₁ {true} {false} = _ 73 | p .F₁ {false} {true} () 74 | p .F₁ {false} {false} = _ 75 | p .F-id {true} = refl 76 | p .F-id {false} = refl 77 | p .F-∘ {true} {true} {true} f g = refl 78 | p .F-∘ {true} {true} {false} f g = refl 79 | p .F-∘ {true} {false} {false} f g = refl 80 | p .F-∘ {false} {false} {false} f g = refl 81 | 82 | p-is-full : is-full p 83 | p-is-full {true} {true} _ = inc (false , refl) 84 | p-is-full {true} {false} _ = inc (false , refl) 85 | p-is-full {false} {false} _ = inc (false , refl) 86 | 87 | p*-is-full : is-full (postcompose p {D = ∙⤮∙}) 88 | p*-is-full = assume p p-is-full 89 | 90 | F G : Functor ∙⤮∙ C 91 | F .F₀ _ = true 92 | F .F₁ f = f 93 | F .F-id = refl 94 | F .F-∘ _ _ = refl 95 | G .F₀ _ = false 96 | G .F₁ f = f 97 | G .F-id = refl 98 | G .F-∘ _ _ = refl 99 | 100 | impossible : F => G → ⊥ 101 | impossible θ = not-no-fixed (sym (θ .is-natural _ _ true)) 102 | 103 | pθ : p F∘ F => p F∘ G 104 | pθ .η = _ 105 | pθ .is-natural _ _ _ = refl 106 | 107 | θ : ∥ F => G ∥ 108 | θ = fst <$> p*-is-full pθ 109 | 110 | contradiction : ⊥ 111 | contradiction = rec! impossible θ 112 | -------------------------------------------------------------------------------- /src-1lab/PresheafExponential.agda: -------------------------------------------------------------------------------- 1 | open import Cat.Prelude 2 | open import Cat.Functor.Base 3 | open import Cat.Functor.Naturality 4 | open import Cat.Instances.Presheaf.Limits 5 | open import Cat.Instances.Presheaf.Exponentials 6 | open import Cat.Diagram.Exponential 7 | open import Cat.Diagram.Product 8 | import Cat.Reasoning 9 | 10 | module PresheafExponential {ℓ} {C : Precategory ℓ ℓ} where 11 | 12 | module C = Cat.Reasoning C 13 | module PSh = Cat.Reasoning (PSh ℓ C) 14 | open Binary-products (PSh ℓ C) (PSh-products _ C) 15 | open Cartesian-closed (PSh-closed C) 16 | 17 | open Functor 18 | open _=>_ 19 | 20 | module _ b a where 21 | open Exponential (has-exp a b) 22 | renaming (B^A to infixr 50 _^_) 23 | using () public 24 | 25 | module _ (K L M : PSh.Ob) where 26 | 27 | internal-currying : M ^ (K ⊗₀ L) PSh.≅ (M ^ K) ^ L 28 | internal-currying = PSh.make-iso 29 | (λ where 30 | .η n f .η q (v , y) .η p (u , x) → f .η p (v C.∘ u , x , L .F₁ u y) 31 | .η n f .η q (v , y) .is-natural → {! !} 32 | .η n f .is-natural → {! !} 33 | .is-natural → {! !}) 34 | (λ where 35 | .η n g .η q (v , x , y) → g .η q (v , y) .η q (C.id , x) 36 | .η n g .is-natural → {! !} 37 | .is-natural → {! !}) 38 | (ext λ n g q v y p u x → 39 | ⌜ g .η p (v C.∘ u , L .F₁ u y) ⌝ .η p (C.id , x) ≡⟨ g .is-natural _ _ u $ₚ (v , y) ηₚ p $ₚ (C.id , x) ⟩ 40 | (M ^ K) .F₁ u (g .η q (v , y)) .η p (C.id , x) ≡⟨⟩ 41 | g .η q (v , y) .η p (⌜ u C.∘ C.id ⌝ , x) ≡⟨ ap! (C.idr u) ⟩ 42 | g .η q (v , y) .η p (u , x) ∎) 43 | {! !} 44 | -------------------------------------------------------------------------------- /src-1lab/Probability.agda: -------------------------------------------------------------------------------- 1 | open import 1Lab.Prelude 2 | 3 | open import Data.Dec 4 | open import Data.Fin 5 | open import Data.Fin.Closure 6 | 7 | module Probability where 8 | 9 | -- “I have two children, (at least) one of whom is a boy born on a Tuesday - 10 | -- what is the probability that both children are boys?” 11 | 12 | -- Simplifying assumptions: gender is binary; gender and day of birth are 13 | -- uniformly distributed. 14 | Gender = Fin 2 15 | Day = Fin 7 16 | Child = Fin 2 17 | 18 | Sample = Child → Day × Gender 19 | 20 | count : (A : Sample → Type) → ⦃ ∀ {s} → Finite (A s) ⦄ → Nat 21 | count A = cardinality {A = Σ Sample A} 22 | 23 | condition : Sample → Type 24 | condition s = ∃[ i ∈ Child ] s i ≡ (1 , 1) 25 | 26 | event : Sample → Type 27 | event s = (i : Child) → s i .snd ≡ 1 28 | 29 | answer : Nat × Nat -- formal fraction 30 | answer = count (λ s → event s × condition s) , count condition 31 | 32 | _ : answer ≡ (13 , 27) 33 | _ = refl 34 | -------------------------------------------------------------------------------- /src-1lab/Skeletons.agda: -------------------------------------------------------------------------------- 1 | open import Cat.Functor.Base 2 | open import Cat.Functor.Equivalence 3 | open import Cat.Functor.FullSubcategory 4 | open import Cat.Functor.Properties 5 | open import Cat.Instances.FinSets 6 | open import Cat.Instances.Sets 7 | open import Cat.Prelude 8 | open import Cat.Skeletal 9 | open import Data.Bool 10 | open import Data.Fin 11 | open import Data.Nat 12 | 13 | import Cat.Reasoning 14 | 15 | open Functor 16 | open is-precat-iso 17 | 18 | {- 19 | Formalising parts of https://math.stackexchange.com/a/4943344, with 20 | finite-dimensional real vector spaces replaced with finite sets 21 | (the situation is exactly the same). 22 | -} 23 | module Skeletons where 24 | 25 | module Sets {ℓ} = Cat.Reasoning (Sets ℓ) 26 | 27 | {- 28 | In the role of the skeletal category whose objects are natural numbers 29 | representing ℝⁿ and whose morphisms are matrices, we use the skeletal 30 | category whose objects are natural numbers representing the standard 31 | finite sets [n] and whose morphisms are functions. 32 | -} 33 | S : Precategory lzero lzero 34 | S = FinSets 35 | 36 | S-is-skeletal : is-skeletal S 37 | S-is-skeletal = FinSets-is-skeletal 38 | 39 | {- 40 | In the role of the univalent category of finite-dimensional real vector 41 | spaces, we use the univalent category of finite sets, here realised as 42 | the *essential image* of the inclusion of S into sets. 43 | Explicitly, an object of C is a set X such that there merely exists a 44 | natural number n such that X ≃ [n]. 45 | Equivalently, an object of C is a set X equipped with a natural number 46 | n such that ∥ X ≃ [n] ∥ (we can extract n from the truncation because 47 | the statements X ≃ [n] are mutually exclusive for distinct n). 48 | C is a Rezk completion of S. 49 | -} 50 | C : Precategory (lsuc lzero) lzero 51 | C = Essential-image Fin→Sets 52 | 53 | C-is-category : is-category C 54 | C-is-category = Essential-image-is-category Fin→Sets Sets-is-category 55 | 56 | {- 57 | Finally, if we remove the truncation (but do not change the morphisms), 58 | we get a skeletal category *isomorphic* to S, because we can contract X 59 | away. This is entirely analogous to the way that the naïve definition 60 | of the image of a function using Σ instead of ∃ yields the domain of 61 | the function (https://1lab.dev/1Lab.Counterexamples.Sigma.html). 62 | -} 63 | C' : Precategory (lsuc lzero) lzero 64 | C' = Restrict {C = Sets _} λ X → Σ[ n ∈ Nat ] Fin→Sets .F₀ n Sets.≅ X 65 | 66 | S→C' : Functor S C' 67 | S→C' .F₀ n = el! (Fin n) , n , Sets.id-iso 68 | S→C' .F₁ f = f 69 | S→C' .F-id = refl 70 | S→C' .F-∘ _ _ = refl 71 | 72 | S≡C' : is-precat-iso S→C' 73 | S≡C' .has-is-ff = id-equiv 74 | S≡C' .has-is-iso = inverse-is-equiv (e .snd) where 75 | e : (Σ[ X ∈ Set lzero ] Σ[ n ∈ Nat ] Fin→Sets .F₀ n Sets.≅ X) ≃ Nat 76 | e = Σ-swap₂ ∙e Σ-contract λ n → is-contr-ΣR Sets-is-category 77 | 78 | {- 79 | Since C is a Rezk completion of S, we should expect to have a fully 80 | faithful and essentially surjective functor S → C. 81 | -} 82 | 83 | S→C : Functor S C 84 | S→C = Essential-inc Fin→Sets 85 | 86 | S→C-is-ff : is-fully-faithful S→C 87 | S→C-is-ff = ff→Essential-inc-ff Fin→Sets Fin→Sets-is-ff 88 | 89 | S→C-is-eso : is-eso S→C 90 | S→C-is-eso = Essential-inc-eso Fin→Sets 91 | 92 | {- 93 | However, this functor is *not* an equivalence of categories: in order 94 | to obtain a functor going the other way, we would have to choose an 95 | enumeration of every finite set in a coherent way. This is a form of 96 | global choice, which is just false in homotopy type theory 97 | (https://1lab.dev/1Lab.Counterexamples.GlobalChoice.html). 98 | -} 99 | 100 | module _ (S≃C : is-equivalence S→C) where private 101 | open is-equivalence S≃C renaming (F⁻¹ to C→S) 102 | module C = Cat.Reasoning C 103 | 104 | module _ (X : Set lzero) (e : ∥ ⌞ X ⌟ ≃ Fin 2 ∥) where 105 | c : C.Ob 106 | c = X , ((λ e → 2 , equiv→iso (e e⁻¹)) <$> e) 107 | 108 | chosen : ⌞ X ⌟ 109 | chosen with C→S .F₀ c | counit.ε c | counit-iso c 110 | ... | suc n | ε | _ = ε 0 111 | ... | zero | ε | ε-inv = absurd (case e of λ e → 112 | zero≠suc (Fin-injective (iso→equiv (sub-iso→super-iso _ (C.invertible→iso ε ε-inv)) ∙e e))) 113 | 114 | b : Bool 115 | b = chosen (el! Bool) enumeration 116 | 117 | swap : Bool ≡ Bool 118 | swap = ua (not , not-is-equiv) 119 | 120 | p : PathP (λ i → swap i) b b 121 | p = ap₂ chosen (n-ua _) prop! 122 | 123 | ¬S≃C : ⊥ 124 | ¬S≃C = not-no-fixed (from-pathp⁻ p) 125 | -------------------------------------------------------------------------------- /src-1lab/SplitMonoSet.agda: -------------------------------------------------------------------------------- 1 | open import Cat.Prelude 2 | import Cat.Reasoning 3 | open import 1Lab.Classical 4 | open import Data.Dec 5 | open import Data.Sum 6 | 7 | -- If every split monomorphism with inhabited domain splits in Sets then excluded middle holds. 8 | module SplitMonoSet where 9 | 10 | module Sets = Cat.Reasoning (Sets lzero) 11 | 12 | module _ (every-mono-splits : ∀ {A B} (a : ∥ ⌞ A ⌟ ∥) (f : Sets.Hom A B) (f-mono : Sets.is-monic {a = A} {B} f) → Sets.is-split-monic {a = A} {B} f) where 13 | lem : LEM 14 | lem P = ∥-∥-out! do 15 | Sets.make-retract f⁻¹ ret ← f-split 16 | pure (go (f⁻¹ (inr tt)) λ p → ret $ₚ inr p) 17 | where 18 | A : Set lzero 19 | A = el! (⊤ ⊎ ⌞ P ⌟) 20 | B : Set lzero 21 | B = el! (⊤ ⊎ ⊤) 22 | f : Sets.Hom A B 23 | f = ⊎-map _ _ 24 | f-mono : Sets.is-monic {a = A} {B} f 25 | f-mono = embedding→monic {f = f} $ injective→is-embedding! λ where 26 | {inl _} {inl _} p → refl 27 | {inl _} {inr _} p → absurd (inl≠inr p) 28 | {inr _} {inl _} p → absurd (inr≠inl p) 29 | {inr _} {inr _} p → ap inr prop! 30 | f-split : Sets.is-split-monic {a = A} {B} f 31 | f-split = every-mono-splits (inc (inl _)) f λ {c} → f-mono {c} 32 | go : (f⁻¹r : ∣ A ∣) → (∀ p → f⁻¹r ≡ inr p) → Dec ∣ P ∣ 33 | go (inl _) l = no λ p → inl≠inr (l p) 34 | go (inr p) l = yes p 35 | -------------------------------------------------------------------------------- /src-1lab/SyntheticCategoricalDuality.lagda.md: -------------------------------------------------------------------------------- 1 | ```agda 2 | open import 1Lab.Reflection.Regularity 3 | open import 1Lab.Path.Cartesian 4 | open import 1Lab.Reflection hiding (absurd) 5 | 6 | open import Cat.Functor.Equivalence.Path 7 | open import Cat.Functor.Equivalence 8 | open import Cat.Prelude hiding (_[_↦_]) 9 | 10 | open import Data.Fin 11 | ``` 12 | 13 | A synthetic account of categorical duality, based on an idea by [**David Wärn**](https://dwarn.se/). 14 | 15 | The theory of categories has a fundamental S₂-symmetry that swaps "source" 16 | and "target", which can be expressed synthetically by defining categories 17 | in the context of the delooping BS₂. 18 | By choosing as our delooping the type of 2-element types, this amounts 19 | to defining categories relative to an arbitrary 2-element type X, which 20 | we can think of as the set {source, target} except we've forgotten 21 | which is which. 22 | Then, instantiating this with a chosen 2-element type recovers usual 23 | categories, and the non-trivial symmetry of BS₂ automatically gives 24 | a symmetry of the type of categories which coincides with the usual 25 | categorical opposite. 26 | 27 | ```agda 28 | module SyntheticCategoricalDuality where 29 | ``` 30 | 31 |
Some auxiliary definitions 32 | 33 | ```agda 34 | private variable 35 | ℓ o h : Level 36 | X O : Type ℓ 37 | H : O → Type ℓ 38 | a b c : O 39 | i j k : X 40 | 41 | excluded-middle : ∀ {x y z : Bool} → x ≠ y → y ≠ z → x ≡ z 42 | excluded-middle {true} {y} {true} x≠y y≠z = refl 43 | excluded-middle {true} {y} {false} x≠y y≠z = absurd (x≠y (sym (x≠false→x≡true y y≠z))) 44 | excluded-middle {false} {y} {true} x≠y y≠z = absurd (x≠y (sym (x≠true→x≡false y y≠z))) 45 | excluded-middle {false} {y} {false} x≠y y≠z = refl 46 | 47 | instance 48 | Extensional-Bool-map 49 | : ∀ {ℓ ℓr} {C : Bool → Type ℓ} → ⦃ e : ∀ {b} → Extensional (C b) ℓr ⦄ 50 | → Extensional ((b : Bool) → C b) ℓr 51 | Extensional-Bool-map ⦃ e ⦄ .Pathᵉ f g = 52 | e .Pathᵉ (f false) (g false) × e .Pathᵉ (f true) (g true) 53 | Extensional-Bool-map ⦃ e ⦄ .reflᵉ f = 54 | e .reflᵉ (f false) , e .reflᵉ (f true) 55 | Extensional-Bool-map ⦃ e ⦄ .idsᵉ .to-path (false≡ , true≡) = funext λ where 56 | true → e .idsᵉ .to-path true≡ 57 | false → e .idsᵉ .to-path false≡ 58 | Extensional-Bool-map ⦃ e ⦄ .idsᵉ .to-path-over (false≡ , true≡) = 59 | Σ-pathp (e .idsᵉ .to-path-over false≡) (e .idsᵉ .to-path-over true≡) 60 | 61 | Extensional-Bool-homotopy 62 | : ∀ {ℓ ℓr} {C : Bool → Type ℓ} → ⦃ e : ∀ {b} {x y : C b} → Extensional (x ≡ y) ℓr ⦄ 63 | → {f g : (b : Bool) → C b} 64 | → Extensional (f ≡ g) ℓr 65 | Extensional-Bool-homotopy ⦃ e ⦄ {f} {g} .Pathᵉ p q = 66 | e .Pathᵉ (p $ₚ false) (q $ₚ false) × e .Pathᵉ (p $ₚ true) (q $ₚ true) 67 | Extensional-Bool-homotopy ⦃ e ⦄ .reflᵉ p = 68 | e .reflᵉ (p $ₚ false) , e .reflᵉ (p $ₚ true) 69 | Extensional-Bool-homotopy ⦃ e ⦄ .idsᵉ .to-path (false≡ , true≡) = funext-square λ where 70 | true → e .idsᵉ .to-path true≡ 71 | false → e .idsᵉ .to-path false≡ 72 | Extensional-Bool-homotopy ⦃ e ⦄ .idsᵉ .to-path-over (false≡ , true≡) = 73 | Σ-pathp (e .idsᵉ .to-path-over false≡) (e .idsᵉ .to-path-over true≡) 74 | 75 | Bool-η : (b : Bool → O) → if (b true) (b false) ≡ b 76 | Bool-η b = ext (refl , refl) 77 | ``` 78 |
79 | 80 | ```agda 81 | -- We define X-(pre)categories relative to a 2-element type X. 82 | module X (o h : Level) (X : Type) (e : ∥ X ≃ Bool ∥) where 83 | ``` 84 | 85 |
Some more auxiliary definitions 86 | 87 | ```agda 88 | private instance 89 | Finite-X : Finite X 90 | Finite-X = ⦇ Equiv→listing (e <&> _e⁻¹) auto ⦈ 91 | 92 | Discrete-X : Discrete X 93 | Discrete-X = Finite→Discrete 94 | 95 | H-Level-X : H-Level X 2 96 | H-Level-X = Finite→H-Level 97 | 98 | _[_↦_] : (X → O) → X → O → X → O 99 | _[_↦_] b x m i = ifᵈ i ≡? x then m else b i 100 | 101 | assign-id : (b : X → O) → (x : X) → b [ x ↦ b x ] ≡ b 102 | assign-id b x = ext go where 103 | go : ∀ i → (b [ x ↦ b x ]) i ≡ b i 104 | go i with i ≡? x 105 | ... | yes p = ap b (sym p) 106 | ... | no _ = refl 107 | 108 | assign-const : (b : X → O) (i j : X) → j ≠ i → b [ j ↦ b i ] ≡ λ _ → b i 109 | assign-const b i j j≠i = ext go where 110 | go : ∀ k → (b [ j ↦ b i ]) k ≡ b i 111 | go k with k ≡? j 112 | ... | yes _ = refl 113 | ... | no k≠j = ap b $ ∥-∥-out! do 114 | e ← e 115 | pure (subst (λ X → {x y z : X} → x ≠ y → y ≠ z → x ≡ z) 116 | (ua (e e⁻¹)) excluded-middle k≠j j≠i) 117 | 118 | degenerate 119 | : (H : (X → O) → Type h) (b : X → O) (x : X) (f : H b) (id : H (λ _ → b x)) (i : X) 120 | → H (b [ i ↦ b x ]) 121 | -- degenerate H b x f id i with i ≡ᵢ? x 122 | -- ... | yes reflᵢ = subst H (sym (assign-id b x)) f 123 | -- ... | no i≠x = subst H (sym (assign-const b x i (i≠x ⊙ Id≃path.from))) id 124 | -- NOTE performing the with-translation manually somehow results in fewer transports when X = Bool and x = i. 125 | -- I'm not sure what's happening here... 126 | degenerate H b x f id i = go (i ≡ᵢ? x) where 127 | go : Dec (i ≡ᵢ x) → H (b [ i ↦ b x ]) 128 | go (yes reflᵢ) = subst H (sym (assign-id b x)) f 129 | go (no i≠x) = subst H (sym (assign-const b x i (i≠x ⊙ Id≃path.from))) id 130 | ``` 131 |
132 | 133 | ```agda 134 | record XPrecategory : Type (lsuc (o ⊔ h)) where 135 | no-eta-equality 136 | 137 | field 138 | Ob : Type o 139 | 140 | -- Hom is a family indexed over "X-pairs" of objects, or boundaries. 141 | Hom : (X → Ob) → Type h 142 | Hom-set : (b : X → Ob) → is-set (Hom b) 143 | 144 | -- The identity lives over the constant pair. 145 | id : ∀ {x} → Hom λ _ → x 146 | 147 | -- Composition takes an outer boundary b, a middle object and an 148 | -- X-pair of morphisms with the appropriate boundaries and returns 149 | -- a morphism with boundary b. 150 | compose : (b : X → Ob) (m : Ob) → ((x : X) → Hom (b [ x ↦ m ])) → Hom b 151 | 152 | -- We can (and must) state both unit laws at once: given a "direction" x : X 153 | -- and a morphism f with boundary b, we can form the X-pair {f, id} 154 | -- where id lies in the direction x from f, and ask that the 155 | -- composite equal f. 156 | compose-id 157 | : (b : X → Ob) (f : Hom b) (x : X) 158 | → compose b (b x) (degenerate Hom b x f id) ≡ f 159 | 160 | -- TODO: associativity 161 | -- assoc 162 | -- : (b : X → Ob) (m n : Ob) (x : X) 163 | -- → compose b m (λ i → {! !}) ≡ compose b n {! !} 164 | ``` 165 | 166 |
Some lemmas about paths between X-precategories 167 | 168 | ```agda 169 | private 170 | hom-set : ∀ (C : XPrecategory) {b} → is-set (C .XPrecategory.Hom b) 171 | hom-set C = C .XPrecategory.Hom-set _ 172 | 173 | instance 174 | hlevel-proj-xhom : hlevel-projection (quote XPrecategory.Hom) 175 | hlevel-proj-xhom .hlevel-projection.has-level = quote hom-set 176 | hlevel-proj-xhom .hlevel-projection.get-level _ = pure (lit (nat 2)) 177 | hlevel-proj-xhom .hlevel-projection.get-argument (c v∷ _) = pure c 178 | hlevel-proj-xhom .hlevel-projection.get-argument _ = typeError [] 179 | 180 | private unquoteDecl record-iso = declare-record-iso record-iso (quote XPrecategory) 181 | 182 | XPrecategory-path 183 | : ∀ {C D : XPrecategory} (let module C = XPrecategory C; module D = XPrecategory D) 184 | → (ob≡ : C.Ob ≡ D.Ob) 185 | → (hom≡ : PathP (λ i → (X → ob≡ i) → Type h) C.Hom D.Hom) 186 | → (id≡ : PathP (λ i → ∀ {x} → hom≡ i (λ _ → x)) C.id D.id) 187 | → (compose≡ : PathP (λ i → ∀ (b : X → ob≡ i) (m : ob≡ i) (f : ∀ x → hom≡ i (b [ x ↦ m ])) → hom≡ i b) C.compose D.compose) 188 | → C ≡ D 189 | XPrecategory-path ob≡ hom≡ id≡ compose≡ = Iso.injective record-iso 190 | $ Σ-pathp ob≡ $ Σ-pathp hom≡ $ Σ-pathp prop! 191 | $ Σ-pathp id≡ $ Σ-pathp compose≡ $ hlevel 0 .centre 192 | ``` 193 |
194 | 195 | ```agda 196 | open X using (XPrecategory; XPrecategory-path) 197 | 198 | -- We recover categories by choosing a 2-element type X with designated 199 | -- source and target elements. Here we pick the booleans with 200 | -- the convention that true = source and false = target. 201 | 2Precategory : (o h : Level) → Type (lsuc (o ⊔ h)) 202 | 2Precategory o h = XPrecategory o h Bool (inc id≃) 203 | 204 | module _ {o h : Level} where 205 | module B = X o h Bool (inc id≃) 206 | 207 | Precategory→2Precategory : Precategory o h → 2Precategory o h 208 | Precategory→2Precategory C = C' where 209 | module C = Precategory C 210 | open XPrecategory 211 | C' : 2Precategory o h 212 | C' .Ob = C.Ob 213 | C' .Hom b = C.Hom (b true) (b false) 214 | C' .Hom-set b = C.Hom-set _ _ 215 | C' .id = C.id 216 | C' .compose b m f = f true C.∘ f false 217 | C' .compose-id b f true = ap₂ C._∘_ (transport-refl f) (transport-refl C.id) ∙ C.idr f 218 | C' .compose-id b f false = ap₂ C._∘_ (transport-refl C.id) (transport-refl f) ∙ C.idl f 219 | -- C' .assoc = ? 220 | 221 | 2Precategory→Precategory : 2Precategory o h → Precategory o h 222 | 2Precategory→Precategory C' = C where 223 | module C' = XPrecategory C' 224 | open Precategory 225 | C : Precategory o h 226 | C .Ob = C'.Ob 227 | C .Hom a b = C'.Hom (if a b) 228 | C .Hom-set a b = C'.Hom-set _ 229 | C .id = subst C'.Hom (ext (refl , refl)) C'.id 230 | C ._∘_ {a} {b} {c} f g = C'.compose (if a c) b λ where 231 | true → subst C'.Hom (ext (refl , refl)) f 232 | false → subst C'.Hom (ext (refl , refl)) g 233 | C .idr {x} {y} f = 234 | ap (C'.compose (if x y) x) (ext 235 | ( sym (subst-∙ C'.Hom _ _ C'.id) 236 | ∙ ap (λ p → subst C'.Hom p C'.id) (ext (∙-idr refl , ∙-idr refl)) 237 | , ap (λ p → subst C'.Hom p f) (ext (refl , refl)))) 238 | ∙ C'.compose-id (if x y) f true 239 | C .idl {x} {y} f = 240 | ap (C'.compose (if x y) y) (ext 241 | ( ap (λ p → subst C'.Hom p f) (ext (refl , refl)) 242 | , sym (subst-∙ C'.Hom _ _ C'.id) 243 | ∙ ap (λ p → subst C'.Hom p C'.id) (ext (∙-idr refl , ∙-idr refl)))) 244 | ∙ C'.compose-id (if x y) f false 245 | C .assoc = {! !} 246 | 247 | Precategory→2Precategory-is-iso : is-iso Precategory→2Precategory 248 | Precategory→2Precategory-is-iso .is-iso.from = 2Precategory→Precategory 249 | Precategory→2Precategory-is-iso .is-iso.rinv C' = XPrecategory-path _ _ _ _ 250 | refl 251 | (ext λ b → ap C'.Hom (Bool-η b)) 252 | (funextP' λ {a} → to-pathp⁻ (ap (λ p → subst C'.Hom p C'.id) (ext (refl , refl)))) 253 | (funextP λ b → funextP λ m → funext-dep-i1 λ f → 254 | let 255 | path : PathP (λ i → C'.Hom (Bool-η b i)) 256 | (C'.compose (if (b true) (b false)) m λ x → coe1→0 (λ i → C'.Hom (Bool-η b i B.[ x ↦ m ])) (f x)) 257 | (C'.compose b m f) 258 | path i = C'.compose (Bool-η b i) m 259 | λ x → coe1→i (λ i → C'.Hom (Bool-η b i B.[ x ↦ m ])) i (f x) 260 | in 261 | ap (C'.compose (if (b true) (b false)) m) (ext 262 | ( sym (subst-∙ C'.Hom _ _ (f false)) 263 | ∙ ap (λ p → subst C'.Hom p (f false)) (ext (∙-idr refl , ∙-idr refl)) 264 | , sym (subst-∙ C'.Hom _ _ (f true)) 265 | ∙ ap (λ p → subst C'.Hom p (f true)) (ext (∙-idr refl , ∙-idr refl)))) 266 | ◁ path) 267 | where module C' = XPrecategory C' 268 | Precategory→2Precategory-is-iso .is-iso.linv C = Precategory-path F (iso id-equiv id-equiv) 269 | where 270 | module C = Precategory C 271 | open Functor 272 | F : Functor (2Precategory→Precategory (Precategory→2Precategory C)) C 273 | F .F₀ o = o 274 | F .F₁ f = f 275 | F .F-id = transport-refl C.id 276 | F .F-∘ f g = ap₂ C._∘_ (transport-refl f) (transport-refl g) 277 | 278 | Precategory≃2Precategory : Precategory o h ≃ 2Precategory o h 279 | Precategory≃2Precategory = Iso→Equiv (Precategory→2Precategory , Precategory→2Precategory-is-iso) 280 | 281 | -- We get categorical duality from the action of the X-category construction 282 | -- on the non-trivial path Bool ≡ Bool, and we check that this agrees 283 | -- with the usual categorical duality. 284 | duality : 2Precategory o h ≡ 2Precategory o h 285 | duality = ap₂ (XPrecategory _ _) (ua not≃) prop! 286 | 287 | _^Xop : 2Precategory o h → 2Precategory o h 288 | _^Xop = transport duality 289 | 290 | dualities-agree 291 | : (C : Precategory o h) 292 | → Precategory→2Precategory C ^Xop ≡ Precategory→2Precategory (C ^op) 293 | dualities-agree C = XPrecategory-path _ _ _ _ 294 | refl 295 | (ext λ b → ap₂ C.Hom (transport-refl _) (transport-refl _)) 296 | Regularity.reduce! 297 | (to-pathp (ext λ b m f → Regularity.reduce!)) 298 | where module C = Precategory C 299 | ``` 300 | -------------------------------------------------------------------------------- /src-1lab/TangentBundlesOfSpheres.lagda.md: -------------------------------------------------------------------------------- 1 | ```agda 2 | open import 1Lab.Path.Cartesian 3 | open import 1Lab.Path.Reasoning 4 | open import 1Lab.Prelude 5 | 6 | open import Algebra.Group.Concrete.Abelian 7 | open import Algebra.Group.Concrete 8 | 9 | open import Data.Set.Truncation 10 | open import Data.Bool 11 | open import Data.Int 12 | open import Data.Nat 13 | open import Data.Sum 14 | 15 | open import Homotopy.Space.Suspension.Properties 16 | open import Homotopy.Connectedness.Automation 17 | open import Homotopy.Space.Suspension 18 | open import Homotopy.Connectedness 19 | open import Homotopy.Space.Circle 20 | open import Homotopy.Space.Sphere 21 | open import Homotopy.Base 22 | 23 | open import Meta.Idiom 24 | ``` 25 | 26 | A formalisation of the first part of [The tangent bundles of spheres](https://www.youtube.com/watch?v=9T9B9XBjVpk) 27 | by David Jaz Myers, Ulrik Buchholtz, Dan Christensen and Egbert Rijke, up until 28 | the proof of the hairy ball theorem (except I don't have enough homotopy theory 29 | to conclude that n-1 must be odd from `flipΣⁿ ≡ id`). 30 | 31 | ```agda 32 | module TangentBundlesOfSpheres where 33 | 34 | record Functorial (M : Effect) : Typeω where 35 | private module M = Effect M 36 | field 37 | ⦃ Map-Functorial ⦄ : Map M 38 | map-id : ∀ {ℓ} {A : Type ℓ} → map {M} {A = A} id ≡ id 39 | map-∘ 40 | : ∀ {ℓ ℓ' ℓ''} {A : Type ℓ} {B : Type ℓ'} {C : Type ℓ''} 41 | → {f : B → C} {g : A → B} 42 | → map {M} (f ∘ g) ≡ map f ∘ map g 43 | 44 | map-iso : ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} 45 | → (e : A ≃ B) → is-iso (map (Equiv.to e)) 46 | map-iso e .is-iso.from = map (Equiv.from e) 47 | map-iso e .is-iso.rinv mb = 48 | map (Equiv.to e) (map (Equiv.from e) mb) ≡˘⟨ map-∘ $ₚ mb ⟩ 49 | map ⌜ Equiv.to e ∘ Equiv.from e ⌝ mb ≡⟨ ap! (funext (Equiv.ε e)) ⟩ 50 | map id mb ≡⟨ map-id $ₚ mb ⟩ 51 | mb ∎ 52 | map-iso e .is-iso.linv ma = 53 | map (Equiv.from e) (map (Equiv.to e) ma) ≡˘⟨ map-∘ $ₚ ma ⟩ 54 | map ⌜ Equiv.from e ∘ Equiv.to e ⌝ ma ≡⟨ ap! (funext (Equiv.η e)) ⟩ 55 | map id ma ≡⟨ map-id $ₚ ma ⟩ 56 | ma ∎ 57 | 58 | map≃ 59 | : ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} 60 | → (e : A ≃ B) → M.₀ A ≃ M.₀ B 61 | map≃ e = _ , is-iso→is-equiv (map-iso e) 62 | 63 | map-transport 64 | : ∀ {ℓ} {A : Type ℓ} {B : Type ℓ} 65 | → (p : A ≡ B) → map (transport p) ≡ transport (ap M.₀ p) 66 | map-transport {A = A} p i = comp (λ i → M.₀ A → M.₀ (p i)) (∂ i) λ where 67 | j (j = i0) → map-id i 68 | j (i = i0) → map (funextP (transport-filler p) j) 69 | j (i = i1) → funextP (transport-filler (ap M.₀ p)) j 70 | 71 | open Functorial ⦃ ... ⦄ 72 | 73 | is-natural 74 | : ∀ {M N : Effect} (let module M = Effect M; module N = Effect N) ⦃ _ : Map M ⦄ ⦃ _ : Map N ⦄ 75 | → (f : ∀ {ℓ} {A : Type ℓ} → M.₀ A → N.₀ A) → Typeω 76 | is-natural f = 77 | ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} {g : A → B} 78 | → ∀ a → map g (f a) ≡ f (map g a) 79 | 80 | -- Operations on suspensions: functorial action, flipping 81 | 82 | instance 83 | Map-Susp : Map (eff Susp) 84 | Map-Susp .Map.map f N = N 85 | Map-Susp .Map.map f S = S 86 | Map-Susp .Map.map f (merid a i) = merid (f a) i 87 | 88 | Functorial-Susp : Functorial (eff Susp) 89 | Functorial-Susp .Functorial.Map-Functorial = Map-Susp 90 | Functorial-Susp .Functorial.map-id = funext $ Susp-elim _ refl refl λ _ _ → refl 91 | Functorial-Susp .Functorial.map-∘ = funext $ Susp-elim _ refl refl λ _ _ → refl 92 | 93 | flipΣ : ∀ {ℓ} {A : Type ℓ} → Susp A → Susp A 94 | flipΣ N = S 95 | flipΣ S = N 96 | flipΣ (merid a i) = merid a (~ i) 97 | 98 | flipΣ∙ : ∀ {n} → Sⁿ (suc n) →∙ Sⁿ (suc n) 99 | flipΣ∙ = flipΣ , sym (merid N) 100 | 101 | flipΣ-involutive : ∀ {ℓ} {A : Type ℓ} → (p : Susp A) → flipΣ (flipΣ p) ≡ p 102 | flipΣ-involutive = Susp-elim _ refl refl λ _ _ → refl 103 | 104 | flipΣ≃ : ∀ {ℓ} {A : Type ℓ} → Susp A ≃ Susp A 105 | flipΣ≃ = flipΣ , is-involutive→is-equiv flipΣ-involutive 106 | 107 | flipΣ-natural : is-natural flipΣ 108 | flipΣ-natural = Susp-elim _ refl refl λ _ _ → refl 109 | 110 | twist : ∀ {ℓ} {A : Type ℓ} {a b : A} {p q : a ≡ b} (α : p ≡ q) 111 | → PathP (λ i → PathP (λ j → α i j ≡ α j (~ i)) 112 | (λ k → p (~ i ∧ k)) 113 | (λ k → q (~ i ∨ ~ k))) 114 | (λ j k → p (j ∨ k)) 115 | (λ j k → q (j ∧ ~ k)) 116 | twist α i j k = hcomp (∂ i ∨ ∂ j ∨ ∂ k) λ where 117 | l (l = i0) → α (I-interp k i j) (I-interp k j (~ i)) 118 | l (i = i0) → α (~ l ∧ k ∧ j) (k ∨ j) 119 | l (i = i1) → α (l ∨ ~ k ∨ j) (~ k ∧ j) 120 | l (j = i0) → α (~ l ∧ ~ k ∧ i) (k ∧ ~ i) 121 | l (j = i1) → α (l ∨ k ∨ i) (~ k ∨ ~ i) 122 | l (k = i0) → α i j 123 | l (k = i1) → α j (~ i) 124 | 125 | -- Flipping ΣΣA along the first axis is homotopic to flipping along the second axis, 126 | -- by rotating 180°. 127 | rotateΣ : ∀ {ℓ} {A : Type ℓ} → map flipΣ ≡ flipΣ {A = Susp A} 128 | rotateΣ = funext $ Susp-elim _ (merid N) (sym (merid S)) ( 129 | Susp-elim _ (flip₁ (double-connection _ _)) (double-connection _ _) 130 | λ a i j k → hcomp (∂ j ∨ ∂ k) λ where 131 | l (l = i0) → merid (merid a j) i 132 | l (j = i0) → merid N (I-interp l i k) 133 | l (j = i1) → merid S (I-interp l i (~ k)) 134 | l (k = i0) → twist (λ i j → merid (merid a i) j) (~ i) j (~ l) 135 | l (k = i1) → twist (λ i j → merid (merid a i) j) j i l) 136 | 137 | Susp-ua→ 138 | : ∀ {ℓ ℓ'} {A B : Type ℓ} {C : Type ℓ'} 139 | → {e : A ≃ B} {f : Susp A → C} {g : Susp B → C} 140 | → (∀ sa → f sa ≡ g (map (e .fst) sa)) 141 | → PathP (λ i → Susp (ua e i) → C) f g 142 | Susp-ua→ h i N = h N i 143 | Susp-ua→ h i S = h S i 144 | Susp-ua→ {g = g} h i (merid a j) = hcomp (∂ i ∨ ∂ j) λ where 145 | k (k = i0) → g (merid (unglue a) j) 146 | k (i = i0) → h (merid a j) (~ k) 147 | k (i = i1) → g (merid a j) 148 | k (j = i0) → h N (i ∨ ~ k) 149 | k (j = i1) → h S (i ∨ ~ k) 150 | 151 | -- The tangent bundles of spheres 152 | 153 | Tⁿ⁻¹ : ∀ n → Sⁿ⁻¹ n → Type 154 | θⁿ⁻¹ : ∀ n → (p : Sⁿ⁻¹ n) → Susp (Tⁿ⁻¹ n p) ≃ Sⁿ⁻¹ n 155 | 156 | Tⁿ⁻¹ zero () 157 | Tⁿ⁻¹ (suc n) = Susp-elim _ 158 | (Sⁿ⁻¹ n) 159 | (Sⁿ⁻¹ n) 160 | λ p → ua (θⁿ⁻¹ n p e⁻¹ ∙e flipΣ≃ ∙e θⁿ⁻¹ n p) 161 | 162 | θⁿ⁻¹ zero () 163 | θⁿ⁻¹ (suc n) = Susp-elim _ 164 | id≃ 165 | flipΣ≃ 166 | λ p → Σ-prop-pathp! $ Susp-ua→ $ happly $ sym $ 167 | let module θ = Equiv (θⁿ⁻¹ n p) in 168 | flipΣ ∘ map (θ.to ∘ flipΣ ∘ θ.from) ≡⟨ flipΣ ∘⟨ map-∘ ⟩ 169 | flipΣ ∘ map θ.to ∘ map (flipΣ ∘ θ.from) ≡⟨ flipΣ ∘ map _ ∘⟨ map-∘ ⟩ 170 | flipΣ ∘ map θ.to ∘ map flipΣ ∘ map θ.from ≡⟨ flipΣ ∘ map _ ∘⟨ rotateΣ ⟩∘ map _ ⟩ 171 | flipΣ ∘ map θ.to ∘ flipΣ ∘ map θ.from ≡⟨ flipΣ ∘⟨ funext flipΣ-natural ⟩∘ map _ ⟩ 172 | flipΣ ∘ flipΣ ∘ map θ.to ∘ map θ.from ≡⟨ funext flipΣ-involutive ⟩∘⟨refl ⟩ 173 | map θ.to ∘ map θ.from ≡⟨ funext (is-iso.rinv (map-iso (θⁿ⁻¹ n p))) ⟩ 174 | id ∎ 175 | 176 | antipodeⁿ⁻¹ : ∀ n → Sⁿ⁻¹ n ≃ Sⁿ⁻¹ n 177 | antipodeⁿ⁻¹ zero = id≃ 178 | antipodeⁿ⁻¹ (suc n) = map≃ (antipodeⁿ⁻¹ n) ∙e flipΣ≃ 179 | 180 | θN : ∀ n → (p : Sⁿ⁻¹ n) → θⁿ⁻¹ n p .fst N ≡ p 181 | θN (suc n) = Susp-elim _ refl refl λ p → transpose $ 182 | ap sym (∙-idl _ ∙ ∙-idl _ ∙ ∙-elimr (∙-idl _ ∙ ∙-idl _ ∙ ∙-idr _ ∙ ∙-idl _ ∙ ∙-idl _ ∙ ∙-idl _)) 183 | ∙ ap merid (θN n p) 184 | 185 | θS : ∀ n → (p : Sⁿ⁻¹ n) → θⁿ⁻¹ n p .fst S ≡ Equiv.to (antipodeⁿ⁻¹ n) p 186 | θS (suc n) = Susp-elim _ refl refl λ p → transpose $ 187 | ap sym (∙-idl _ ∙ ∙-idl _ ∙ ∙-elimr (∙-idl _ ∙ ∙-idl _ ∙ ∙-idr _ ∙ ∙-idl _ ∙ ∙-idl _ ∙ ∙-idl _)) 188 | ∙ ap (sym ∘ merid) (θS n p) 189 | 190 | cⁿ⁻¹ : ∀ n → (p : Sⁿ⁻¹ n) → Tⁿ⁻¹ n p → p ≡ Equiv.to (antipodeⁿ⁻¹ n) p 191 | cⁿ⁻¹ n p t = sym (θN n p) ∙ ap (θⁿ⁻¹ n p .fst) (merid t) ∙ θS n p 192 | 193 | flipΣⁿ : ∀ n → Sⁿ⁻¹ n → Sⁿ⁻¹ n 194 | flipΣⁿ zero = id 195 | flipΣⁿ (suc n) = if⁺ even-or-odd n then flipΣ else id 196 | 197 | flipΣⁿ⁺² : ∀ n → map (map (flipΣⁿ n)) ≡ flipΣⁿ (suc (suc n)) 198 | flipΣⁿ⁺² zero = ap map map-id ∙ map-id 199 | flipΣⁿ⁺² (suc n) with even-or-odd n 200 | ... | inl e = ap map rotateΣ ∙ rotateΣ 201 | ... | inr o = ap map map-id ∙ map-id 202 | 203 | antipode≡flip : ∀ n → Equiv.to (antipodeⁿ⁻¹ n) ≡ flipΣⁿ n 204 | antipode≡flip zero = refl 205 | antipode≡flip (suc zero) = ap (flipΣ ∘_) map-id 206 | antipode≡flip (suc (suc n)) = 207 | flipΣ ∘ map (flipΣ ∘ map (antipodeⁿ⁻¹ n .fst)) ≡⟨ flipΣ ∘⟨ map-∘ ⟩ 208 | flipΣ ∘ map flipΣ ∘ map (map (antipodeⁿ⁻¹ n .fst)) ≡⟨ flipΣ ∘⟨ rotateΣ ⟩∘ map _ ⟩ 209 | flipΣ ∘ flipΣ ∘ map (map (antipodeⁿ⁻¹ n .fst)) ≡⟨ funext flipΣ-involutive ⟩∘⟨refl ⟩ 210 | map (map (antipodeⁿ⁻¹ n .fst)) ≡⟨ ap (map ∘ map) (antipode≡flip n) ⟩ 211 | map (map (flipΣⁿ n)) ≡⟨ flipΣⁿ⁺² n ⟩ 212 | flipΣⁿ (suc (suc n)) ∎ 213 | 214 | -- If the tangent bundle of the n-sphere admits a section for even n, then we get 215 | -- a homotopy between flipΣ and the identity. 216 | section→homotopy : ∀ n → ((p : Sⁿ⁻¹ n) → Tⁿ⁻¹ n p) → flipΣⁿ n ≡ id 217 | section→homotopy n sec = sym $ funext (λ p → cⁿ⁻¹ n p (sec p)) ∙ antipode≡flip n 218 | 219 | -- Now to prove that this in turn implies that n-1 is odd requires a bit of 220 | -- homotopy theory in order to define the degrees of (unpointed!) maps of spheres. 221 | 222 | degree∙ : ∀ n → (Sⁿ (suc n) →∙ Sⁿ (suc n)) → Int 223 | degree∙ zero f = ΩS¹≃integers .fst (ap (transport SuspS⁰≡S¹) (Ωⁿ≃Sⁿ-map 1 .fst f)) 224 | degree∙ (suc n) = {! πₙ(Sⁿ) ≃ ℤ !} 225 | 226 | degree∙-map : ∀ n f → degree∙ (suc n) (map (f .fst) , refl) ≡ degree∙ n f 227 | degree∙-map n f = {! the isomorphisms above should be compatible with suspension !} 228 | 229 | degree∙-id : ∀ n → degree∙ n id∙ ≡ 1 230 | degree∙-id zero = refl 231 | degree∙-id (suc n) = ap (degree∙ (suc n)) p ∙∙ degree∙-map n id∙ ∙∙ degree∙-id n 232 | where 233 | p : id∙ ≡ (map id , refl) 234 | p = Σ-pathp (sym map-id) refl 235 | 236 | degree∙-flipΣ : ∀ n → degree∙ n flipΣ∙ ≡ -1 237 | degree∙-flipΣ zero = refl -- neat. 238 | degree∙-flipΣ (suc n) = ap (degree∙ (suc n)) p ∙∙ degree∙-map n flipΣ∙ ∙∙ degree∙-flipΣ n 239 | where 240 | p : flipΣ∙ ≡ (map flipΣ , refl) 241 | p = Σ-pathp (sym rotateΣ) (λ i j → merid N (~ i ∧ ~ j)) 242 | 243 | -- In order to define degrees of unpointed maps, we show that the function that 244 | -- forgets the pointing of a map Sⁿ →∙ Sⁿ is a bijection (up to homotopy). 245 | -- For n = 1, this is due to the fact that S¹ is the delooping of an abelian 246 | -- group; for n > 1, we can use the fact that the n-sphere is simply connected. 247 | Sⁿ-class-injective 248 | : ∀ n f → (p q : f N ≡ N) 249 | → ∥ Path (Sⁿ (suc n) →∙ Sⁿ (suc n)) (f , p) (f , q) ∥ 250 | Sⁿ-class-injective zero f p q = inc (S¹-cohomology.injective refl) 251 | where 252 | open ConcreteGroup 253 | Sⁿ⁼¹-concrete : ConcreteGroup lzero 254 | Sⁿ⁼¹-concrete .B = Sⁿ 1 255 | Sⁿ⁼¹-concrete .has-is-connected = is-connected→is-connected∙ (Sⁿ⁻¹-is-connected 2) 256 | Sⁿ⁼¹-concrete .has-is-groupoid = subst is-groupoid (sym SuspS⁰≡S¹) S¹-is-groupoid 257 | 258 | Sⁿ⁼¹≡S¹ : Sⁿ⁼¹-concrete ≡ S¹-concrete 259 | Sⁿ⁼¹≡S¹ = ConcreteGroup-path (Σ-path SuspS⁰≡S¹ refl) 260 | 261 | Sⁿ⁼¹-ab : is-concrete-abelian Sⁿ⁼¹-concrete 262 | Sⁿ⁼¹-ab = subst is-concrete-abelian (sym Sⁿ⁼¹≡S¹) S¹-concrete-abelian 263 | 264 | module S¹-cohomology = Equiv 265 | (first-concrete-abelian-group-cohomology 266 | Sⁿ⁼¹-concrete Sⁿ⁼¹-concrete Sⁿ⁼¹-ab) 267 | Sⁿ-class-injective (suc n) f p q = ap (f ,_) <$> simply-connected p q 268 | 269 | Sⁿ-class 270 | : ∀ n 271 | → ∥ (Sⁿ (suc n) →∙ Sⁿ (suc n)) ∥₀ 272 | → ∥ (⌞ Sⁿ (suc n) ⌟ → ⌞ Sⁿ (suc n) ⌟) ∥₀ 273 | Sⁿ-class n = ∥-∥₀-rec (hlevel 2) λ (f , _) → inc f 274 | 275 | Sⁿ-pointed≃unpointed 276 | : ∀ n 277 | → ∥ (Sⁿ (suc n) →∙ Sⁿ (suc n)) ∥₀ 278 | ≃ ∥ (⌞ Sⁿ (suc n) ⌟ → ⌞ Sⁿ (suc n) ⌟) ∥₀ 279 | Sⁿ-pointed≃unpointed n .fst = Sⁿ-class n 280 | Sⁿ-pointed≃unpointed n .snd = injective-surjective→is-equiv! (inj _ _) surj 281 | where 282 | inj : ∀ f g → Sⁿ-class n f ≡ Sⁿ-class n g → f ≡ g 283 | inj = elim! λ f ptf g ptg f≡g → 284 | ∥-∥₀-path.from do 285 | f≡g ← ∥-∥₀-path.to f≡g 286 | J (λ g _ → ∀ ptg → ∥ (f , ptf) ≡ (g , ptg) ∥) 287 | (Sⁿ-class-injective n f ptf) 288 | f≡g ptg 289 | 290 | surj : is-surjective (Sⁿ-class n) 291 | surj = ∥-∥₀-elim (λ _ → hlevel 2) λ f → do 292 | pointed ← connected (f N) N 293 | pure (inc (f , pointed) , refl) 294 | 295 | degree : ∀ n → (⌞ Sⁿ (suc n) ⌟ → ⌞ Sⁿ (suc n) ⌟) → Int 296 | degree n f = ∥-∥₀-rec (hlevel 2) 297 | (degree∙ n) 298 | (Equiv.from (Sⁿ-pointed≃unpointed n) (inc f)) 299 | 300 | degree∙≡degree : ∀ n f∙ → degree n (f∙ .fst) ≡ degree∙ n f∙ 301 | degree∙≡degree n f∙ = ap (∥-∥₀-rec _ _) 302 | (U.injective₂ {x = U.from (inc (f∙ .fst))} {y = inc f∙} (U.ε _) refl) 303 | where module U = Equiv (Sⁿ-pointed≃unpointed n) 304 | 305 | flip≠id : ∀ n → ¬ flipΣ ≡ id {A = Sⁿ⁻¹ (suc n)} 306 | flip≠id zero h = subst (Susp-elim _ ⊤ ⊥ (λ ())) (h $ₚ S) _ 307 | flip≠id (suc n) h = negsuc≠pos $ 308 | -1 ≡˘⟨ degree∙-flipΣ n ⟩ 309 | degree∙ n flipΣ∙ ≡˘⟨ degree∙≡degree n _ ⟩ 310 | degree n flipΣ ≡⟨ ap (degree n) h ⟩ 311 | degree n id ≡⟨ degree∙≡degree n _ ⟩ 312 | degree∙ n id∙ ≡⟨ degree∙-id n ⟩ 313 | 1 ∎ 314 | 315 | hairy-ball : ∀ n → ((p : Sⁿ⁻¹ n) → Tⁿ⁻¹ n p) → is-even n 316 | hairy-ball zero sec = ∣-zero 317 | hairy-ball (suc n) sec with even-or-odd n | section→homotopy (suc n) sec 318 | ... | inl e | h = absurd (flip≠id n h) 319 | ... | inr o | _ = o 320 | ``` 321 | -------------------------------------------------------------------------------- /src-1lab/Untruncate.agda: -------------------------------------------------------------------------------- 1 | open import 1Lab.Prelude 2 | 3 | -- The identity function on homogeneous types "factors" through the propositional truncation 4 | -- (https://homotopytypetheory.org/2013/10/28/the-truncation-map-_-%E2%84%95-%E2%80%96%E2%84%95%E2%80%96-is-nearly-invertible) 5 | module Untruncate where 6 | 7 | point : ∀ {ℓ} (X : Type ℓ) → X → Type∙ ℓ 8 | point X x = X , x 9 | 10 | is-homogeneous : ∀ {ℓ} → Type ℓ → Type (lsuc ℓ) 11 | is-homogeneous X = ∀ x y → point X x ≡ point X y 12 | 13 | ∥-∥-rec-const 14 | : ∀ {ℓ ℓ'} {A : Type ℓ} {B : Type ℓ'} 15 | → (f : A → B) 16 | → (b : B) 17 | → (∀ x → b ≡ f x) 18 | → ∥ A ∥ → B 19 | ∥-∥-rec-const {A = A} {B} f b f-const x = 20 | ∥-∥-elim {P = λ _ → Singleton b} (λ _ → is-contr→is-prop (contr _ Singleton-is-contr)) 21 | (λ x → f x , f-const x) x .fst 22 | 23 | module old {ℓ} (X : Type ℓ) (x : X) (hom : is-homogeneous X) where 24 | point' : ∥ X ∥ → Type∙ ℓ 25 | point' = ∥-∥-rec-const (point X) (point X x) (hom x) 26 | 27 | myst : (x : ∥ X ∥) → point' x .fst 28 | myst x = point' x .snd 29 | 30 | _ : myst ∘ inc ≡ id 31 | _ = refl 32 | 33 | -- Simplification by David Wärn https://gist.github.com/dwarn/31d7002a5ca8df0443b31501056e357f 34 | module new {ℓ : Level} {X : Type ℓ} where 35 | fam : ∥ X ∥ → n-Type ℓ 0 36 | fam = rec! λ x → el! (Singleton x) 37 | 38 | magic : X → X 39 | magic = fst ∘ centre ∘ is-tr ∘ fam ∘ inc 40 | 41 | _ : magic ≡ id 42 | _ = refl 43 | -------------------------------------------------------------------------------- /src-1lab/YonedaColimit.agda: -------------------------------------------------------------------------------- 1 | open import Cat.Prelude 2 | open import Cat.Functor.Hom 3 | open import Cat.Functor.Base 4 | open import Cat.Functor.Constant 5 | open import Cat.Diagram.Colimit.Base 6 | open import Cat.Diagram.Limit.Base 7 | open import Cat.Diagram.Terminal 8 | open import Cat.Diagram.Initial 9 | open import Cat.Instances.Presheaf.Limits 10 | open import Cat.Instances.Presheaf.Exponentials 11 | 12 | import Cat.Reasoning 13 | 14 | open _=>_ 15 | open make-is-colimit 16 | 17 | module YonedaColimit {o ℓ} (C : Precategory o ℓ) where 18 | 19 | open Cat.Reasoning C 20 | 21 | Δ1 : Terminal (PSh ℓ C) 22 | Δ1 = PSh-terminal _ C 23 | 24 | open Terminal Δ1 25 | 26 | よ-colimit : Colimit (よ C) 27 | よ-colimit = to-colimit (to-is-colimit colim) where 28 | colim : make-is-colimit (よ C) top 29 | colim .ψ c = ! 30 | colim .commutes f = ext λ _ _ → refl 31 | colim .universal eta comm .η x _ = eta x .η x id 32 | colim .universal eta comm .is-natural x y f = ext λ _ → 33 | sym (comm f ηₚ y $ₚ id) ∙∙ ap (eta x .η y) id-comm ∙∙ eta x .is-natural _ _ f $ₚ id 34 | colim .factors eta comm = ext λ x f → 35 | sym (comm f ηₚ x $ₚ id) ∙ ap (eta _ .η x) (idr _) 36 | colim .unique eta comm univ' fac' = ext λ x _ → fac' x ηₚ x $ₚ id 37 | 38 | Δ0 : Initial (PSh ℓ C) 39 | Δ0 = {! Const ? !} 40 | 41 | よ-limit : Limit (よ C) 42 | よ-limit = to-limit (to-is-limit lim) where 43 | lim : make-is-limit (よ C) (Const (el! (Lift _ ⊥))) 44 | lim .make-is-limit.ψ c .η x () 45 | lim .make-is-limit.ψ c .is-natural _ _ _ = ext λ () 46 | lim .make-is-limit.commutes f = ext λ _ () 47 | lim .make-is-limit.universal eps comm .η = {! !} 48 | lim .make-is-limit.universal eps comm .is-natural = {! !} 49 | lim .make-is-limit.factors = {! !} 50 | lim .make-is-limit.unique = {! !} 51 | -------------------------------------------------------------------------------- /src-1lab/src-1lab.agda-lib: -------------------------------------------------------------------------------- 1 | name: cubical-experiments 2 | include: . 3 | depend: 4 | 1lab 5 | flags: 6 | --cubical 7 | --no-load-primitives 8 | --postfix-projections 9 | --allow-unsolved-metas 10 | --rewriting 11 | --guardedness 12 | --erasure 13 | -W noInteractionMetaBoundaries 14 | -W noUnsupportedIndexedMatch 15 | -------------------------------------------------------------------------------- /src/DeMorKan.agda: -------------------------------------------------------------------------------- 1 | open import Cubical.Foundations.Prelude 2 | 3 | -- A silly attempt at implementing composition for the interval, 4 | -- for https://proofassistants.stackexchange.com/questions/2043/is-the-de-morgan-interval-kan 5 | module DeMorKan where 6 | 7 | -- The built-in I lives in its own "non-fibrant" universe, so Agda won't let 8 | -- us express partial elements and subtypes. 9 | -- Hence we define a "wrapper" HIT, but do not make use of its Kan structure! 10 | data Interval : Type where 11 | i0' : Interval 12 | i1' : Interval 13 | inI : i0' ≡ i1' 14 | 15 | module 2D (i j : I) where 16 | ⊔ : I 17 | ⊔ = ~ j ∨ i ∨ ~ i 18 | B L R : I → I 19 | B i = i ∨ ~ i -- 20 | L j = i1 -- replace these with anything (as long as they agree on endpoints) 21 | R j = ~ j -- 22 | horn : Partial ⊔ Interval 23 | horn (j = i0) = inI (B i) 24 | horn (i = i0) = inI (L j) 25 | horn (i = i1) = inI (R j) 26 | filler : Interval [ ⊔ ↦ horn ] 27 | filler = inS (inI ((~ j ∧ B i) ∨ (~ i ∧ L j) ∨ (i ∧ R j))) 28 | 29 | module 3D (i j k : I) where 30 | ⊔ : I 31 | ⊔ = ~ k ∨ ~ i ∨ i ∨ ~ j ∨ j 32 | B L R D U : I → I → I 33 | B i j = i0 34 | L j k = i0 35 | R j k = i0 36 | D i k = i0 37 | U i k = i0 38 | horn : Partial ⊔ Interval 39 | horn (k = i0) = inI (B i j) 40 | horn (i = i0) = inI (L j k) 41 | horn (i = i1) = inI (R j k) 42 | horn (j = i0) = inI (D i k) 43 | horn (j = i1) = inI (U i k) 44 | filler : Interval [ ⊔ ↦ horn ] 45 | filler = inS (inI ((~ k ∧ B i j) ∨ (~ i ∧ L j k) ∨ (i ∧ R j k) ∨ (~ j ∧ D i k) ∨ (j ∧ U i k))) 46 | -------------------------------------------------------------------------------- /src/Erasure.agda: -------------------------------------------------------------------------------- 1 | open import Agda.Primitive renaming (Set to Type; Setω to Typeω) 2 | open import Relation.Binary.PropositionalEquality hiding ([_]) 3 | open import Axiom.Extensionality.Propositional 4 | {-# BUILTIN REWRITE _≡_ #-} 5 | 6 | -- Investigating the erasure modality. See also ErasureOpen 7 | module Erasure where 8 | 9 | private variable 10 | a b : Level 11 | A : Type a 12 | 13 | -- The erased path induction principle J₀ 14 | 15 | J₀-type = 16 | ∀ {a b} {@0 A : Type a} {@0 x : A} (B : (@0 y : A) → @0 x ≡ y → Type b) 17 | → {@0 y : A} (@0 p : x ≡ y) → B x refl → B y p 18 | 19 | -- The Erased monadic modality 20 | 21 | record Erased (@0 A : Type a) : Type a where 22 | constructor [_] 23 | field 24 | @0 erased : A 25 | 26 | open Erased 27 | 28 | η : {@0 A : Type a} → A → Erased A 29 | η x = [ x ] 30 | 31 | μ : {@0 A : Type a} → Erased (Erased A) → Erased A 32 | μ [ [ x ] ] = [ x ] 33 | 34 | -- Paths (Erased A) → Erased (Paths A) 35 | erased-cong : ∀ {a} {@0 A : Type a} {@0 x y : A} → [ x ] ≡ [ y ] → Erased (x ≡ y) 36 | erased-cong p = [ cong erased p ] 37 | 38 | -- Erased (Paths A) → Paths (Erased A) ("erasure extensionality") 39 | []-cong-type = ∀ {a} {@0 A : Type a} {@0 x y : A} → Erased (x ≡ y) → [ x ] ≡ [ y ] 40 | 41 | -- J₀ and []-cong (with their respective computation rules) are interderivable 42 | 43 | module J₀→[]-cong where 44 | postulate 45 | J₀ : J₀-type 46 | J₀-refl 47 | : ∀ {a b} {@0 A : Type a} {@0 x : A} (B : (@0 y : A) → @0 x ≡ y → Type b) (r : B x refl) 48 | → J₀ B refl r ≡ r 49 | {-# REWRITE J₀-refl #-} 50 | 51 | []-cong : []-cong-type 52 | []-cong {x} [ p ] = J₀ (λ y _ → [ x ] ≡ [ y ]) p refl 53 | 54 | []-cong-refl 55 | : ∀ {a} {@0 A : Type a} {@0 x : A} 56 | → []-cong {x = x} [ refl ] ≡ refl 57 | []-cong-refl = refl 58 | 59 | module []-cong→J₀ where 60 | postulate 61 | []-cong : []-cong-type 62 | []-cong-refl 63 | : ∀ {a} {@0 A : Type a} {@0 x : A} 64 | → []-cong {x = x} [ refl ] ≡ refl 65 | {-# REWRITE []-cong-refl #-} 66 | 67 | -- []-cong μ 68 | -- Erased (Paths (Erased A)) → Paths (Erased (Erased A)) → Paths (Erased A) 69 | stable-≡ : ∀ {@0 A : Type a} {x y : Erased A} → Erased (x ≡ y) → x ≡ y 70 | stable-≡ p = cong μ ([]-cong p) 71 | 72 | -- η []-cong erased-cong 73 | -- Paths A → Erased (Paths A) → Paths (Erased A) → Erased (Paths A) 74 | -- Erased (Paths A) → Erased (Paths A) 75 | -- id 76 | []-cong-section' 77 | : ∀ {@0 A : Type a} {@0 x y : A} (p : x ≡ y) 78 | → erased-cong ([]-cong (η p)) ≡ η p 79 | []-cong-section' refl = refl 80 | 81 | -- We can cancel out η by unique elimination and stability of paths in Erased 82 | []-cong-section 83 | : ∀ {@0 A : Type a} {@0 x y : A} (@0 p : x ≡ y) 84 | → erased-cong ([]-cong [ p ]) ≡ [ p ] 85 | []-cong-section p = stable-≡ [ []-cong-section' p ] 86 | 87 | J₀ : J₀-type 88 | J₀ B {y} p r = subst (λ ([ p ]) → B y p) ([]-cong-section p) b' 89 | where 90 | b' : B y (cong erased ([]-cong [ p ])) 91 | b' = J (λ ([ y ]) p → B y (cong erased p)) ([]-cong [ p ]) r 92 | 93 | J₀-refl 94 | : ∀ {a b} {@0 A : Type a} {@0 x : A} (B : (@0 y : A) → @0 x ≡ y → Type b) (r : B x refl) 95 | → J₀ B refl r ≡ r 96 | J₀-refl B r = refl 97 | 98 | -- Function extensionality implies erasure extensionality 99 | module funext→[]-cong where 100 | postulate 101 | funext : ∀ {a b} → Extensionality a b 102 | 103 | -- Direct proof, extracted from "Logical properties of a modality for erasure" (Danielsson 2019) 104 | 105 | -- id : Paths (Erased A) → Paths (Erased A) 106 | -- → {funext} 107 | -- Paths (Paths (Erased A) → Erased A) 108 | -- → {uniquely eliminating} 109 | -- Paths (Erased (Paths (Erased A)) → Erased A) 110 | -- → {apply p} 111 | -- Paths (Erased A) 112 | stable-≡ : ∀ {@0 A : Type a} {x y : Erased A} → Erased (x ≡ y) → x ≡ y 113 | stable-≡ {A} {x} {y} [ p ] = 114 | cong (λ (f : x ≡ y → Erased A) → [ f p .erased ]) 115 | (funext (λ (p : x ≡ y) → p)) 116 | 117 | -- η stable-≡ 118 | -- Erased (Paths A) → Erased (Paths (Erased A)) → Paths (Erased A) 119 | []-cong : []-cong-type 120 | []-cong [ p ] = stable-≡ [ cong η p ] 121 | 122 | -- Alternative proof: ignoring some details, the types of funext and []-cong look very similar: 123 | -- funext : Functions (Paths A) → Paths (Functions A) 124 | -- []-cong : Erased (Paths A) → Paths (Erased A) 125 | -- 126 | -- If we have inductive types with erased constructors, then we can 127 | -- present erasure as an *open modality* generated by the subterminal 128 | -- object with a single erased point (see ErasureOpen): 129 | 130 | data Compiling : Type where 131 | @0 compiling : Compiling 132 | 133 | ○_ : Type a → Type a 134 | ○ A = Compiling → A 135 | 136 | ○'_ : ○ Type a → Type a 137 | ○' A = (n : Compiling) → A n 138 | 139 | E→○ : {A : ○ Type a} → Erased (A compiling) → ○' A 140 | E→○ a compiling = a .erased 141 | 142 | ○→E : {A : ○ Type a} → ○' A → Erased (A compiling) 143 | ○→E f .erased = f compiling 144 | 145 | E→○→E : {A : ○ Type a} → (a : Erased (A compiling)) → ○→E (E→○ {A = A} a) ≡ a 146 | E→○→E _ = refl 147 | 148 | -- We don't actually need this 149 | ○→E→○ : {A : ○ Type a} → (f : ○' A) → E→○ (○→E f) ≡ f 150 | ○→E→○ f = funext (E→○ [ refl {x = f compiling} ]) 151 | 152 | -- Since Erased is (equivalent to) a function type, erasure extensionality/[]-cong 153 | -- is a special case of function extensionality: 154 | -- 155 | -- funext 156 | -- Erased (Paths A) ≃ (Compiling → Paths A) → Paths (Compiling → A) ≃ Paths (Erased A) 157 | []-cong' : []-cong-type 158 | []-cong' {A} {x} {y} p = cong ○→E x'≡y' 159 | where 160 | x' y' : ○' E→○ [ A ] 161 | x' = E→○ [ x ] 162 | y' = E→○ [ y ] 163 | 164 | x'≡y' : x' ≡ y' 165 | x'≡y' = funext (E→○ p) 166 | -------------------------------------------------------------------------------- /src/NaiveFunext.agda: -------------------------------------------------------------------------------- 1 | {-# OPTIONS --without-K #-} 2 | open import Agda.Primitive renaming (Set to Type) 3 | open import Data.Product 4 | open import Data.Product.Properties 5 | open import Relation.Binary.PropositionalEquality 6 | 7 | -- Naïve function extensionality implies function extensionality (HoTT book exercise 4.9). 8 | -- This is actually weaker as we assume ~ → ≡ for *dependent* functions. 9 | module NaiveFunext where 10 | 11 | private variable 12 | ℓ ℓ' : Level 13 | A : Type ℓ 14 | B : A → Type ℓ 15 | f g : (a : A) → B a 16 | 17 | _~_ : (f g : (a : A) → B a) → Type _ 18 | f ~ g = ∀ a → f a ≡ g a 19 | 20 | happly : f ≡ g → f ~ g 21 | happly {f = f} p = subst (λ x → f ~ x) p λ _ → refl 22 | 23 | cong-proj₂ : ∀ {a b} {c : B a} {d : B b} → (p : (a , c) ≡ (b , d)) → subst B (cong proj₁ p) c ≡ d 24 | cong-proj₂ {c = c} refl = refl 25 | 26 | singleton-is-contr : ∀ {a : A} {s : Σ A (a ≡_)} → (a , refl) ≡ s 27 | singleton-is-contr {s = _ , refl} = refl 28 | 29 | module _ 30 | (ext : ∀ {ℓ ℓ'} {A : Type ℓ} {B : A → Type ℓ'} {f g : (a : A) → B a} → f ~ g → f ≡ g) 31 | where 32 | 33 | module _ (f : (a : A) → B a) where 34 | from : ((a : A) → Σ _ (f a ≡_)) → Σ _ (f ~_) 35 | from p = (λ a → p a .proj₁) , (λ a → p a .proj₂) 36 | 37 | to : Σ _ (f ~_) → ((a : A) → Σ _ (f a ≡_)) 38 | to g = λ a → g .proj₁ a , g .proj₂ a 39 | 40 | -- Homotopies form an identity system, which is equivalent to function extensionality. 41 | htpy-is-contr : (g : Σ _ (f ~_)) → (f , λ _ → refl) ≡ g 42 | htpy-is-contr g = cong from p 43 | where 44 | p : (λ a → f a , refl) ≡ to g 45 | p = ext λ _ → singleton-is-contr 46 | -------------------------------------------------------------------------------- /src/NatChurchMonoid.agda: -------------------------------------------------------------------------------- 1 | open import Cubical.Algebra.Monoid 2 | open import Cubical.Algebra.Monoid.Instances.Nat 3 | open import Cubical.Algebra.Semigroup 4 | open import Cubical.Data.Nat 5 | open import Cubical.Data.Sigma 6 | open import Cubical.Foundations.Prelude 7 | open import Cubical.Foundations.Function 8 | open import Cubical.Foundations.Isomorphism 9 | open import Cubical.Foundations.Structure 10 | 11 | -- ℕ ≃ (m : Monoid) → ⟨ m ⟩ → ⟨ m ⟩ 12 | module NatChurchMonoid where 13 | 14 | MEndo : Type₁ 15 | MEndo = (m : Monoid ℓ-zero) → ⟨ m ⟩ → ⟨ m ⟩ 16 | 17 | isNatural : MEndo → Type₁ 18 | isNatural me = {m1 m2 : Monoid ℓ-zero} (f : MonoidHom m1 m2) → me m2 ∘ f .fst ≡ f .fst ∘ me m1 19 | 20 | isPropIsNatural : (me : MEndo) → isProp (isNatural me) 21 | isPropIsNatural me a b i {m1} {m2} f j x = m2 .snd .MonoidStr.isMonoid .IsMonoid.isSemigroup .IsSemigroup.is-set (me m2 (f .fst x)) (f .fst (me m1 x)) (funExt⁻ (a f) x) (funExt⁻ (b f) x) i j 22 | 23 | MEndoNatural : Type₁ 24 | MEndoNatural = Σ MEndo isNatural 25 | 26 | -- A generalised Church encoding for ℕ. This boils down to the fact that the forgetful functor 27 | -- U : Mon → Set is represented by ℕ ≃ F 1, followed by the Yoneda lemma. 28 | ℕ≃MEndoNatural : Iso ℕ MEndoNatural 29 | ℕ≃MEndoNatural = iso mtimes on1 mtimes-on1 on1-mtimes where 30 | 31 | mtimes : ℕ → MEndoNatural 32 | mtimes zero .fst (_ , monoidstr ε _·_ m) = (λ _ → ε) 33 | mtimes zero .snd f = funExt λ _ → sym (f .snd .IsMonoidHom.presε) 34 | mtimes (suc n) .fst ms@(t , monoidstr ε _·_ m) = (λ x → x · mtimes n .fst ms x) 35 | mtimes (suc n) .snd {m1} {m2@(_ , monoidstr _ _·_ m)} f = funExt λ x → cong (f .fst x ·_) (λ i → mtimes n .snd f i x) ∙ sym (f .snd .IsMonoidHom.pres· x (mtimes n .fst m1 x)) 36 | 37 | mtimes-hom : (m : Monoid ℓ-zero) (x : ⟨ m ⟩) → MonoidHom NatMonoid m 38 | mtimes-hom m x = (λ n → mtimes n .fst m x) , monoidequiv refl (λ n n' → mtimes-+ n n') where 39 | mtimes-+ : (n n' : ℕ) {m : Monoid ℓ-zero} {x : ⟨ m ⟩} → mtimes (n + n') .fst m x ≡ m .snd .MonoidStr._·_ (mtimes n .fst m x) (mtimes n' .fst m x) 40 | mtimes-+ zero n' {m} = sym (m .snd .MonoidStr.isMonoid .IsMonoid.·IdL _) 41 | mtimes-+ (suc n) n' {m} {x} = cong (m .snd .MonoidStr._·_ x) (mtimes-+ n n') ∙ m .snd .MonoidStr.isMonoid .IsMonoid.isSemigroup .IsSemigroup.·Assoc _ _ _ 42 | 43 | on1 : MEndoNatural → ℕ 44 | on1 me = me .fst NatMonoid 1 45 | 46 | on1-mtimes : (n : ℕ) → on1 (mtimes n) ≡ n 47 | on1-mtimes zero = refl 48 | on1-mtimes (suc n) = cong suc (on1-mtimes n) 49 | 50 | mtimes-on1 : (me : MEndoNatural) → mtimes (on1 me) ≡ me 51 | mtimes-on1 me = Σ≡Prop isPropIsNatural (λ i m x → p m x i) where 52 | p : (m : Monoid ℓ-zero) (x : ⟨ m ⟩) → mtimes (on1 me) .fst m x ≡ me .fst m x 53 | p m x = sym (funExt⁻ (me .snd (mtimes-hom m x)) 1) 54 | ∙ cong (me .fst m) (m .snd .MonoidStr.isMonoid .IsMonoid.·IdR _) 55 | -------------------------------------------------------------------------------- /src/Shapes.agda: -------------------------------------------------------------------------------- 1 | open import Cubical.Foundations.Prelude 2 | open import Cubical.Foundations.Path 3 | open import Cubical.Foundations.Isomorphism renaming (Iso to _≃_) 4 | open import Cubical.Foundations.Univalence 5 | open import Cubical.Data.Unit renaming (Unit to ⊤) 6 | open import Cubical.Data.Sigma 7 | open import Cubical.Data.Int 8 | open import Cubical.Relation.Nullary 9 | 10 | -- — 11 | data Interval : Type where 12 | l : Interval 13 | r : Interval 14 | seg : l ≡ r 15 | 16 | Interval-isContr : isContr Interval 17 | Interval-isContr = l , paths where 18 | paths : (x : Interval) → l ≡ x 19 | paths l = refl 20 | paths r = seg 21 | paths (seg i) j = seg (i ∧ j) 22 | 23 | Interval-loops : (x : Interval) → x ≡ x 24 | Interval-loops l = refl 25 | Interval-loops r = refl 26 | Interval-loops (seg i) j = seg i 27 | 28 | -- ○ 29 | data S¹ : Type where 30 | base : S¹ 31 | loop : base ≡ base 32 | 33 | S¹→⊤ : S¹ → ⊤ 34 | S¹→⊤ base = tt 35 | S¹→⊤ (loop i) = tt 36 | ⊤→S¹ : ⊤ → S¹ 37 | ⊤→S¹ tt = base 38 | ⊤→S¹→⊤ : (t : ⊤) → S¹→⊤ (⊤→S¹ t) ≡ t 39 | ⊤→S¹→⊤ tt = refl 40 | -- S¹→⊤→S¹ : (x : S¹) → ⊤→S¹ (S¹→⊤ x) ≡ x 41 | -- S¹→⊤→S¹ base = refl 42 | -- S¹→⊤→S¹ (loop i) j = {! IMPOSSIBLE the point doesn't retract onto the circle! !} 43 | 44 | always-loop : (x : S¹) → x ≡ x 45 | always-loop base = loop 46 | always-loop (loop i) j = 47 | hcomp (λ where k (i = i0) → loop (j ∨ ~ k) 48 | k (i = i1) → loop (j ∧ k) 49 | k (j = i0) → loop (i ∨ ~ k) 50 | k (j = i1) → loop (i ∧ k)) 51 | base 52 | 53 | loop-induction : {ℓ : Level} {P : base ≡ base → Type ℓ} 54 | → (pprop : ∀ p → isProp (P p)) 55 | → (prefl : P refl) 56 | → (ploop : ∀ p → P p → P (p ∙ loop)) 57 | → (ppool : ∀ p → P p → P (p ∙ sym loop)) 58 | → (p : base ≡ base) → P p 59 | loop-induction {ℓ} {P} pprop prefl ploop ppool = J Q prefl 60 | where 61 | bridge : PathP (λ i → base ≡ loop i → Type ℓ) P P 62 | bridge = toPathP (funExt λ p → isoToPath 63 | (iso (λ x → subst P (compPathr-cancel _ _) (ploop _ x)) 64 | (ppool p) 65 | (λ _ → pprop _ _ _) 66 | (λ _ → pprop _ _ _))) 67 | Q : (x : S¹) → base ≡ x → Type ℓ 68 | Q base p = P p 69 | Q (loop i) p = bridge i p 70 | 71 | data Bool₁ : Type₁ where 72 | false true : Bool₁ 73 | 74 | S¹⋆ : Σ Type (λ A → A) 75 | S¹⋆ = S¹ , base 76 | 77 | flip : S¹ → S¹ 78 | flip base = base 79 | flip (loop i) = loop (~ i) 80 | flip≡ : S¹ ≡ S¹ 81 | flip≡ = isoToPath (iso flip flip inv inv) where 82 | inv : section flip flip 83 | inv base = refl 84 | inv (loop i) = refl 85 | flip⋆ : S¹⋆ ≡ S¹⋆ 86 | flip⋆ i = flip≡ i , base≡base i where 87 | base≡base : PathP (λ i → flip≡ i) base base 88 | base≡base = ua-gluePath _ refl 89 | 90 | Cover : S¹ → Type 91 | Cover base = ℤ 92 | Cover (loop i) = sucPathℤ i 93 | 94 | S¹⋆-auto : (S¹⋆ ≡ S¹⋆) ≡ Bool₁ 95 | S¹⋆-auto = isoToPath (iso to from sec ret) where 96 | isPos : ℤ → Bool₁ 97 | isPos (pos _) = true 98 | isPos _ = false 99 | to : S¹⋆ ≡ S¹⋆ → Bool₁ 100 | to p = isPos (transport (λ i → Cover (loop' i)) 0) where 101 | loop' : base ≡ base 102 | loop' i = comp (λ j → p j .fst) 103 | (λ where j (i = i0) → p j .snd 104 | j (i = i1) → p j .snd) 105 | (loop i) 106 | from : Bool₁ → S¹⋆ ≡ S¹⋆ 107 | from false = flip⋆ 108 | from true = refl 109 | sec : section to from 110 | sec false = refl 111 | sec true = refl 112 | ret : retract to from 113 | ret p = {! !} 114 | 115 | -- ● 116 | data D² : Type where 117 | base² : D² 118 | loop² : base² ≡ base² 119 | disk : refl ≡ loop² 120 | 121 | D²-isContr : isContr D² 122 | D²-isContr = base² , paths where 123 | paths : (x : D²) → base² ≡ x 124 | paths base² = refl 125 | paths (loop² i) j = disk j i 126 | paths (disk i j) k = disk (i ∧ k) j 127 | 128 | D²-isProp : isProp D² 129 | D²-isProp x y = sym (D²-isContr .snd x) ∙ D²-isContr .snd y 130 | 131 | data coeq (X : Type) : Type where 132 | inc : X → coeq X 133 | eq : ∀ x → inc x ≡ inc x 134 | 135 | lemma : ∀ X → coeq X ≃ (X × S¹) 136 | lemma X = iso to from to-from from-to where 137 | to : coeq X → X × S¹ 138 | to (inc x) = x , base 139 | to (eq x i) = x , loop i 140 | from : X × S¹ → coeq X 141 | from (x , base) = inc x 142 | from (x , loop i) = eq x i 143 | to-from : ∀ x → to (from x) ≡ x 144 | to-from (_ , base) = refl 145 | to-from (_ , loop i) = refl 146 | from-to : ∀ x → from (to x) ≡ x 147 | from-to (inc x) = refl 148 | from-to (eq x i) = refl 149 | -------------------------------------------------------------------------------- /src/Torus.agda: -------------------------------------------------------------------------------- 1 | module Torus where 2 | 3 | open import Cubical.Foundations.Prelude 4 | open import Cubical.Foundations.Isomorphism 5 | open import Cubical.Foundations.Equiv 6 | open import Cubical.Foundations.GroupoidLaws 7 | open import Cubical.HITs.Torus 8 | 9 | private 10 | variable 11 | ℓ : Level 12 | A : Type ℓ 13 | 14 | -- 🍩 15 | data T² : Type where 16 | base : T² 17 | p q : base ≡ base 18 | surf : p ∙ q ≡ q ∙ p 19 | 20 | hcomp-inv : {φ : I} (u : I → Partial φ A) (u0 : A [ φ ↦ u i1 ]) 21 | → hcomp u (hcomp (λ k → u (~ k)) (outS u0)) ≡ outS u0 22 | hcomp-inv u u0 i = hcomp-equivFiller (λ k → u (~ k)) u0 (~ i) 23 | 24 | T²≃Torus : T² ≃ Torus 25 | T²≃Torus = isoToEquiv (iso to from to-from from-to) 26 | where 27 | sides : {a : A} (p1 p2 : a ≡ a) (i j k : I) → Partial (i ∨ ~ i ∨ j ∨ ~ j) A 28 | sides p1 p2 i j k (i = i0) = compPath-filler p2 p1 (~ k) j 29 | sides p1 p2 i j k (i = i1) = compPath-filler' p1 p2 (~ k) j 30 | sides p1 p2 i j k (j = i0) = p1 (i ∧ k) 31 | sides p1 p2 i j k (j = i1) = p1 (i ∨ ~ k) 32 | 33 | to : T² → Torus 34 | to base = point 35 | to (p i) = line1 i 36 | to (q j) = line2 j 37 | to (surf i j) = hcomp (λ k → sides line1 line2 (~ i) j (~ k)) (square (~ i) j) 38 | 39 | from : Torus → T² 40 | from point = base 41 | from (line1 i) = p i 42 | from (line2 j) = q j 43 | from (square i j) = hcomp (sides p q i j) (surf (~ i) j) 44 | 45 | to-from : ∀ x → to (from x) ≡ x 46 | to-from point = refl 47 | to-from (line1 i) = refl 48 | to-from (line2 i) = refl 49 | to-from (square i j) = hcomp-inv (sides line1 line2 i j) (inS (square i j)) 50 | 51 | from-to : ∀ x → from (to x) ≡ x 52 | from-to base = refl 53 | from-to (p i) = refl 54 | from-to (q i) = refl 55 | from-to (surf i j) = {! hcomp-inv (λ k → sides p q (~ i) j (~ k)) (inS (surf i j)) !} 56 | -- see https://github.com/agda/cubical/pull/912 for the full proof 57 | -------------------------------------------------------------------------------- /src/src.agda-lib: -------------------------------------------------------------------------------- 1 | name: cubical-experiments 2 | include: . 3 | depend: 4 | standard-library 5 | cubical 6 | flags: 7 | --cubical 8 | --no-import-sorts 9 | --postfix-projections 10 | --hidden-argument-puns 11 | --allow-unsolved-metas 12 | --rewriting 13 | --guardedness 14 | --erasure 15 | -W noInteractionMetaBoundaries 16 | -W noUnsupportedIndexedMatch 17 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: JuliaMono; 3 | src: url("https://cdn.jsdelivr.net/gh/cormullion/juliamono/webfonts/JuliaMono-Medium.woff2"); 4 | font-display: swap; 5 | } 6 | 7 | @font-face { 8 | font-family: JuliaMono; 9 | font-weight: bold; 10 | src: url("https://cdn.jsdelivr.net/gh/cormullion/juliamono/webfonts/JuliaMono-ExtraBold.woff2"); 11 | font-display: swap; 12 | } 13 | 14 | :root { 15 | --background: #080709; 16 | --foreground: white; 17 | --accent: #c15cff; 18 | --comment: hsl(0, 0%, 60%); 19 | --defined: var(--foreground); 20 | --literal: var(--accent); 21 | --keyword: var(--foreground); 22 | --symbol: var(--foreground); 23 | --bound: #c59efd; 24 | --module: var(--literal); 25 | --constructor: var(--literal); 26 | } 27 | 28 | ::selection { 29 | background-color: var(--accent); 30 | color: white; 31 | } 32 | 33 | body { 34 | margin: 0 15%; 35 | font-family: sans-serif; 36 | text-align: justify; 37 | background-color: var(--background); 38 | color: var(--foreground); 39 | } 40 | 41 | pre { 42 | /* Otherwise Firefox takes ages trying to justify
 blocks... */
 43 |   text-align: initial;
 44 | }
 45 | 
 46 | pre, code {
 47 |   font-family: JuliaMono, monospace;
 48 | }
 49 | 
 50 | details {
 51 |   border-inline-start: 4px solid var(--accent);
 52 |   padding-inline-start: 8px;
 53 | }
 54 | 
 55 | details > summary::after {
 56 |   content: '(click to unfold)';
 57 |   color: var(--comment);
 58 | }
 59 | 
 60 | details[open] > summary::after {
 61 |   content: '(click to fold)';
 62 | }
 63 | 
 64 | .anchor::before {
 65 |   content: '🔗';
 66 |   display: inline-block;
 67 |   font-size: 80%;
 68 |   margin-left: 10px;
 69 |   opacity: 0.3;
 70 | }
 71 | 
 72 | .anchor:hover {
 73 |   text-decoration: none;
 74 | }
 75 | 
 76 | h1:hover > .anchor::before, h2:hover > .anchor::before, h3:hover > .anchor::before, h4:hover > .anchor::before, h5:hover > .anchor::before, h6:hover > .anchor::before {
 77 |   opacity: 1;
 78 | }
 79 | 
 80 | :any-link {
 81 |   text-decoration: none;
 82 |   color: var(--module);
 83 | }
 84 | 
 85 | /* Aspects. */
 86 | .Agda .Comment       { color: var(--comment) }
 87 | .Agda .Background    { }
 88 | .Agda .Markup        { }
 89 | .Agda .Keyword       { color: var(--keyword); font-weight: bold; }
 90 | .Agda .String        { color: var(--literal) }
 91 | .Agda .Number        { color: var(--literal) }
 92 | .Agda .Symbol        { color: var(--symbol) }
 93 | .Agda .PrimitiveType { color: var(--defined) }
 94 | .Agda .Pragma        { color: var(--keyword)   }
 95 | .Agda .Operator      {}
 96 | .Agda .Hole          { background: #490764 }
 97 | .Agda .Macro         { color: var(--defined) }
 98 | 
 99 | /* NameKinds. */
100 | .Agda .Bound                  { color: var(--bound)   }
101 | .Agda .Generalizable          { color: var(--bound)   }
102 | .Agda .InductiveConstructor   { color: var(--constructor) }
103 | .Agda .CoinductiveConstructor { color: var(--constructor) }
104 | .Agda .Datatype               { color: var(--defined) }
105 | .Agda .Field                  { color: var(--constructor) }
106 | .Agda .Function               { color: var(--defined) }
107 | .Agda .Module                 { color: var(--module) }
108 | .Agda .Postulate              { color: var(--defined) }
109 | .Agda .Primitive              { color: var(--defined) }
110 | .Agda .Record                 { color: var(--defined) }
111 | 
112 | /* OtherAspects. */
113 | .Agda .DottedPattern        {}
114 | .Agda .UnsolvedMeta         { color: var(--foreground); background: yellow         }
115 | .Agda .UnsolvedConstraint   { color: var(--foreground); background: yellow         }
116 | .Agda .TerminationProblem   { color: var(--foreground); background: #FFA07A        }
117 | .Agda .IncompletePattern    { color: var(--foreground); background: #F5DEB3        }
118 | .Agda .Error                { color: red;   text-decoration: underline }
119 | .Agda .TypeChecks           { color: var(--foreground); background: #ADD8E6        }
120 | .Agda .Deadcode             { color: var(--foreground); background: #808080        }
121 | .Agda .ShadowingInTelescope { color: var(--foreground); background: #808080        }
122 | 
123 | /* Standard attributes. */
124 | .Agda a { text-decoration: none }
125 | .Agda a[href]:hover { background-color: #444; }
126 | .Agda [href].hover-highlight { background-color: #444; }
127 | 


--------------------------------------------------------------------------------