mirror of
https://github.com/urbit/shrub.git
synced 2024-12-03 05:43:18 +03:00
Merge branches 'top-down', 'claydoc-rebase', 'curtis-url-fix' and 'curtis-tutorial-3-4'
Conflicts: urb/zod/pub/docs/dev/hoon/tutorial/2-syntax.mdy added urbit.pill fixes #563 fixes #574
This commit is contained in:
commit
1c1f98591d
@ -4,10 +4,7 @@
|
||||
/? 314
|
||||
/- talk, sole
|
||||
/+ talk, sole
|
||||
/= seed /~ !>(.)
|
||||
/= talk-doc
|
||||
/; |=(a=wain (turn a |=(b=cord [%txt "? {(trip b)}"])))
|
||||
/: /===/pub/doc/talk/help /txt/
|
||||
/= seed /~ !>(.)
|
||||
::
|
||||
::::
|
||||
::
|
||||
@ -913,7 +910,7 @@
|
||||
%unset (unset +.job)
|
||||
%target (target +.job)
|
||||
%probe (probe +.job)
|
||||
%help (help)
|
||||
%help help
|
||||
%say (say +.job)
|
||||
==
|
||||
::
|
||||
@ -921,10 +918,12 @@
|
||||
|= gam=telegram
|
||||
^+ ..sh-work
|
||||
=+ tay=~(. tr man.she (~(has in settings.she) %noob) gam)
|
||||
=. ..sh-work (sh-fact %tan tr-tang:tay)
|
||||
=. ..sh-work (sh-fact tr-fact:tay)
|
||||
sh-prod(active.she `tr-pals:tay)
|
||||
::
|
||||
++ help |=(~ (sh-fact %mor talk-doc)) :: %help
|
||||
++ help
|
||||
(sh-fact %txt "see http://urbit.org/docs/user/talk")
|
||||
::
|
||||
++ glyph
|
||||
|= idx=@
|
||||
=< cha.ole
|
||||
@ -1597,7 +1596,7 @@
|
||||
pa-report-cabal
|
||||
::
|
||||
++ pa-cancel :: unsubscribe from
|
||||
~& [%pa-cancel ost.hid]
|
||||
:: ~& [%pa-cancel ost.hid]
|
||||
%_ .
|
||||
gramsers (~(del by gramsers) ost.hid)
|
||||
groupers (~(del in groupers) ost.hid)
|
||||
@ -1932,6 +1931,9 @@
|
||||
bou=bouquet
|
||||
sep=speech
|
||||
==
|
||||
++ tr-fact ^- sole-effect :: activate effect
|
||||
~[%mor [%tan tr-meta] tr-body]
|
||||
::
|
||||
++ tr-line ^- tape :: one-line print
|
||||
=+ txt=(tr-text =(who our.hid))
|
||||
?: =(~ txt) ""
|
||||
@ -1943,8 +1945,7 @@
|
||||
(~(sn-nick sn man [who (main who)]))
|
||||
(weld baw txt)
|
||||
::
|
||||
++ tr-tang ^- tang
|
||||
%+ welp tr-sep-tang
|
||||
++ tr-meta ^- tang
|
||||
=. wen (sub wen (mod wen (div wen ~s0..0001))) :: round
|
||||
=+ hed=leaf/"{(scow %uv sen)} at {(scow %da wen)}"
|
||||
=+ =< paz=(turn (~(tap by aud)) .)
|
||||
@ -1952,18 +1953,17 @@
|
||||
=+ bok=(turn (sort (~(tap in bou)) aor) smyt)
|
||||
[%rose [" " ~ ~] [hed >who< [%rose [", " "to " ~] paz] bok]]~
|
||||
::
|
||||
++ tr-sep-tang
|
||||
|- ^- tang
|
||||
=< ?+(. . [@ *] [.]~) ^- ?(tank tang) :: wrap single tanks
|
||||
?+ -.sep [>sep<]~
|
||||
%exp palm/[~ "#" " " ~]^~[leaf/(trip p.sep)]
|
||||
%lin leaf/"{?:(p.sep "" "@ ")}{(trip q.sep)}"
|
||||
%non ~
|
||||
%app rose/[": " ~ ~]^~[leaf/"[{(trip p.sep)}]" leaf/(trip q.sep)]
|
||||
%tax leaf/(rend-work-duty p.sep)
|
||||
%url palm/[~ "/" " " ~]^~[leaf/(earf p.sep)]
|
||||
%mor ?~(p.sep ~ (weld $(p.sep t.p.sep) $(sep i.p.sep)))
|
||||
%fat (welp (tr-rend-tors p.sep) $(sep q.sep))
|
||||
++ tr-body
|
||||
|- ^- sole-effect
|
||||
?+ -.sep tan/[>sep<]~
|
||||
%exp tan/~[leaf/"# {(trip p.sep)}"]
|
||||
%lin tan/~[leaf/"{?:(p.sep "" "@ ")}{(trip q.sep)}"]
|
||||
%non tan/~
|
||||
%app tan/~[rose/[": " ~ ~]^~[leaf/"[{(trip p.sep)}]" leaf/(trip q.sep)]]
|
||||
%tax tan/~[leaf/(rend-work-duty p.sep)]
|
||||
%url url/(crip (earf p.sep))
|
||||
%mor mor/(turn p.sep |=(speech ^$(sep +<)))
|
||||
%fat [%mor tan/(tr-rend-tors p.sep) $(sep q.sep) ~]
|
||||
==
|
||||
::
|
||||
++ tr-rend-tors
|
||||
@ -2111,7 +2111,7 @@
|
||||
++ pull ::
|
||||
|= [pax=path]
|
||||
^- [(list move) _+>]
|
||||
~& [%talk-pull src.hid ost.hid pax]
|
||||
:: ~& [%talk-pull src.hid ost.hid pax]
|
||||
=^ moz +>.$ ra-abet:(ra-cancel:ra src.hid pax)
|
||||
[moz +>.$(shells (~(del by shells) ost.hid))]
|
||||
::
|
||||
|
@ -132,7 +132,7 @@
|
||||
ins=(unit (list (pair path cage))) :: inserts
|
||||
dig=(map path cage) :: store diffs
|
||||
dif=(unit (list (trel path lobe cage))) :: changes
|
||||
muc=(map path cage) :: store miso
|
||||
muc=(map path cage) :: store mutations
|
||||
muh=(map path lobe) :: store hashes
|
||||
mut=(unit (list (trel path lobe cage))) :: mutations
|
||||
mim=(map path mime) :: mime cache
|
||||
@ -492,6 +492,60 @@
|
||||
$(p.lem t.p.lem)
|
||||
==
|
||||
::
|
||||
:: This is the entry point to the commit flow. It deserves some
|
||||
:: explaining, since it's rather long and convoluted.
|
||||
::
|
||||
:: We take a `++nori`, which is either a label-add request or a `++soba`,
|
||||
:: which is a list of changes. If it's a label, it's easy and we just pass
|
||||
:: it to `++edit:ze`.
|
||||
::
|
||||
:: If the given `++nori` is a list of file changes, then we our goal is to
|
||||
:: convert the list of `++miso` changes to `++misu` changes. In other
|
||||
:: words, turn the `++nori` into a `++nuri`. Then, we pass it to
|
||||
:: `++edit:ze`, which applies the changes to our state, and then we
|
||||
:: check out the new revision. XX reword
|
||||
::
|
||||
:: Anyhow, enough of high-level wishy-washy talk. It's time to get down to
|
||||
:: the nitty-gritty.
|
||||
::
|
||||
:: When we get a list of `++miso` changes, we split them into four types:
|
||||
:: deletions, insertions, diffs (i.e. change from diff), and mutations
|
||||
:: (i.e. change from new data). We do four different things with them.
|
||||
::
|
||||
:: For deletions, we just fill in `del` in `++dork` with a list of the
|
||||
:: deleted files.
|
||||
::
|
||||
:: For insertions, we distinguish bewtween `%hoon` files and all other
|
||||
:: files. For `%hoon` files, we just store them to `ink` in `++dork` so
|
||||
:: that we add diff them directly. `%hoon` files have to be treated
|
||||
:: specially to make the bootstrapping sequence work, since the mark
|
||||
:: definitions are themselves `%hoon` files.
|
||||
::
|
||||
:: For the other files, we make a `%tabl` compound ford request to convert
|
||||
:: the data for the new file to the the mark indicated by the last span in
|
||||
:: the path.
|
||||
::
|
||||
:: For diffs, we make a `%tabl` compound ford request to apply the diff to
|
||||
:: the existing content. We also store the diffs in `dig` in `++dork`.
|
||||
::
|
||||
:: For mutations, we make a `%tabl` compound ford request to convert the
|
||||
:: given new data to the mark of the already-existing file. Later on in
|
||||
:: `++take-castify` we'll create the ford request to actually perform the
|
||||
:: diff. We also store the mutations in `muc` in `++dork`. I'm pretty
|
||||
:: sure that's useless because who cares about the original data.
|
||||
:: XX delete `muc`.
|
||||
::
|
||||
:: Finally, for performance reasons we cache any of the data that came in
|
||||
:: as a `%mime` cage. We do this because many commits come from unix,
|
||||
:: where they're passed in as `%mime` and need to be turned back into it
|
||||
:: for the ergo. We cache both `%hoon` and non-`%hoon` inserts and
|
||||
:: mutations.
|
||||
::
|
||||
:: At this point, the flow of control goes through the three ford requests
|
||||
:: back to `++take-inserting`, `++take-diffing`, and `++take-castifying`,
|
||||
:: which itself leads to `++take-mutating`. Once each of those has
|
||||
:: completed, we end up at `++apply-edit`, where our unified story picks up
|
||||
:: again.
|
||||
++ edit :: apply changes
|
||||
|= [wen=@da lem=nori]
|
||||
^+ +>
|
||||
@ -608,31 +662,7 @@
|
||||
==
|
||||
==
|
||||
::
|
||||
++ silkify
|
||||
|= [wen=@da pax=path mis=miso]
|
||||
^- [duct path note]
|
||||
~| [%silkifying pax -.mis]
|
||||
:- hen
|
||||
?+ -.mis !!
|
||||
%mut
|
||||
:- [%diffing (scot %p her) syd (scot %da wen) pax]
|
||||
:^ %f %exec our :+ ~ [her syd %da wen]
|
||||
^- silk
|
||||
:+ %diff
|
||||
(lobe-to-silk:ze pax (~(got by q:(aeon-to-yaki:ze let.dom)) pax))
|
||||
=+ (slag (dec (lent pax)) pax)
|
||||
=+ ?~(- %$ i.-)
|
||||
[%cast - [%$ p.mis]]
|
||||
::
|
||||
%ins
|
||||
:- [%casting (scot %p her) syd (scot %da wen) pax]
|
||||
:^ %f %exec our :+ ~ [her syd %da wen]
|
||||
^- silk
|
||||
=+ (slag (dec (lent pax)) pax)
|
||||
=+ ?~(- %$ i.-)
|
||||
[%cast - [%$ p.mis]]
|
||||
==
|
||||
::
|
||||
:: See ++edit for a description of the commit flow.
|
||||
++ apply-edit
|
||||
|= wen=@da
|
||||
^+ +>
|
||||
@ -664,6 +694,7 @@
|
||||
([echo(dok ~)]:.(+>.$ +.hat) wen %& sim)
|
||||
(checkout-ankh(lat.ran lat.ran.+.hat) u.-.hat)
|
||||
::
|
||||
:: See ++edit for a description of the commit flow.
|
||||
++ take-inserting
|
||||
|= [wen=@da res=gage]
|
||||
^+ +>
|
||||
@ -684,6 +715,7 @@
|
||||
~|(%clay-take-inserting-strange-path-mark !!)
|
||||
[((hard path) q.q.pax) cay]
|
||||
::
|
||||
:: See ++edit for a description of the commit flow.
|
||||
++ take-diffing
|
||||
|= [wen=@da res=gage]
|
||||
^+ +>
|
||||
@ -706,6 +738,7 @@
|
||||
=+ paf=((hard path) q.q.pax)
|
||||
[paf (page-to-lobe:ze [p q.q]:cay) (~(got by dig.u.dok) paf)]
|
||||
::
|
||||
:: See ++edit for a description of the commit flow.
|
||||
++ take-castify
|
||||
|= [wen=@da res=gage]
|
||||
^+ +>
|
||||
@ -736,6 +769,7 @@
|
||||
[%diff - [%$ cay]]
|
||||
==
|
||||
::
|
||||
:: See ++edit for a description of the commit flow.
|
||||
++ take-mutating
|
||||
|= [wen=@da res=gage]
|
||||
^+ +>
|
||||
@ -760,6 +794,7 @@
|
||||
=+ paf=((hard path) q.q.pax)
|
||||
`[paf (~(got by muh.u.dok) paf) cay]
|
||||
::
|
||||
:: See ++edit for a description of the commit flow.
|
||||
++ take-patch
|
||||
|= res=gage
|
||||
^+ +>
|
||||
@ -844,6 +879,7 @@
|
||||
(lobe-to-silk:ze a p.-)
|
||||
==
|
||||
::
|
||||
:: See ++edit for a description of the commit flow.
|
||||
++ take-ergo
|
||||
|= res=gage
|
||||
^+ +>
|
||||
@ -870,6 +906,7 @@
|
||||
[(slag len pax) (~(got by can) pax)]
|
||||
==
|
||||
::
|
||||
:: See ++edit for a description of the commit flow.
|
||||
++ checkout-ankh
|
||||
|= hat=(map path lobe)
|
||||
^+ +>
|
||||
@ -2692,7 +2729,6 @@
|
||||
..^$(ruf ruf.old)
|
||||
::
|
||||
++ scry :: inspect
|
||||
:: Make a request
|
||||
|= [fur=(unit (set monk)) ren=@tas his=ship syd=desk lot=coin tyl=path]
|
||||
^- (unit (unit cage))
|
||||
:: ~& scry/[ren `path`[(scot %p his) syd ~(rent co lot) tyl]]
|
||||
|
@ -1388,7 +1388,7 @@
|
||||
%plan (cope (abut:(meow p.kas q.kas) cof r.kas) faun)
|
||||
%reef (faun cof pit)
|
||||
%ride
|
||||
%+ cool |.(leaf/"ford: ride {<`@p`(mug kas)>}")
|
||||
%+ cool |.(leaf/"ford: build failed}")
|
||||
%+ cope $(kas q.kas)
|
||||
%- tabl-run
|
||||
|= [cof=cafe cay=cage]
|
||||
|
@ -673,7 +673,7 @@
|
||||
?. (~(has by sup.ged) ost) .
|
||||
=+ soy=(~(get by qel.ged) ost)
|
||||
?: |(?=(~ soy) =(0 u.soy))
|
||||
~& [%ap-fill-under [our dap] q.q.pry ost]
|
||||
:: ~& [%ap-fill-under [our dap] q.q.pry ost]
|
||||
+
|
||||
=. u.soy (dec u.soy)
|
||||
:: ~& [%ap-fill-sub [[our dap] q.q.pry ost] u.soy]
|
||||
@ -1049,7 +1049,7 @@
|
||||
::
|
||||
++ ap-pull :: load delete
|
||||
=+ wim=(~(get by sup.ged) ost)
|
||||
?~ wim ~&(%ap-pull-none +)
|
||||
?~ wim + :: ~&(%ap-pull-none +)
|
||||
=: sup.ged (~(del by sup.ged) ost)
|
||||
qel.ged (~(del by qel.ged) ost)
|
||||
==
|
||||
@ -1062,7 +1062,7 @@
|
||||
+>+
|
||||
::
|
||||
++ ap-kill :: queue kill
|
||||
~& [%ap-kill dap ost]
|
||||
:: ~& [%ap-kill dap ost]
|
||||
(ap-give:ap-pull %quit ~)
|
||||
::
|
||||
++ ap-take :: non-diff gall take
|
||||
@ -1070,7 +1070,7 @@
|
||||
^+ +>
|
||||
=+ cug=(ap-find cog pax)
|
||||
?~ cug
|
||||
~& [%ap-take-none cog pax]
|
||||
:: ~& [%ap-take-none cog pax]
|
||||
+>.$
|
||||
=^ cam +>.$
|
||||
%+ ap-call q.u.cug
|
||||
|
@ -2389,6 +2389,7 @@
|
||||
[%mor ~] :: newline
|
||||
[%sag p=path q=*] :: save to jamfile
|
||||
[%sav p=path q=@] :: save to file
|
||||
[%url p=@t] :: activate url
|
||||
== ::
|
||||
++ dill-belt :: new belt
|
||||
$% [%aro p=?(%d %l %r %u)] :: arrow key
|
||||
@ -2413,6 +2414,7 @@
|
||||
[%out p=(list ,@c)] :: send output line
|
||||
[%sag p=path q=*] :: save to jamfile
|
||||
[%sav p=path q=@] :: save to file
|
||||
[%url p=@t] :: activate url
|
||||
== ::
|
||||
++ flog :: sent to %dill
|
||||
$% [%crud p=@tas q=(list tank)] ::
|
||||
@ -2427,6 +2429,7 @@
|
||||
++ gift-dill :: out result <-$
|
||||
$% [%bbye ~] :: reset prompt
|
||||
[%blit p=(list blit)] :: terminal output
|
||||
[%burl p=@t] :: activate url
|
||||
[%init p=@p] :: set owner
|
||||
[%logo ~] :: logout
|
||||
[%mass p=mass] :: memory usage
|
||||
|
@ -663,6 +663,7 @@
|
||||
%sag +>(+> (se-blit fec))
|
||||
%sav +>(+> (se-blit fec))
|
||||
%txt $(fec [%tan [%leaf p.fec]~])
|
||||
%url +>(+> (se-blit fec))
|
||||
==
|
||||
::
|
||||
++ ta-dog :: change cursor
|
||||
|
@ -1,17 +1,24 @@
|
||||
---
|
||||
logo: black
|
||||
title: Hoon
|
||||
sort: 2
|
||||
title: Hoon
|
||||
---
|
||||
|
||||
<div class="short">
|
||||
|
||||
# Hoon
|
||||
|
||||
Hoon is a strict, typed, pure functional language. This site is served by an
|
||||
urbit written in Hoon.
|
||||
Hoon is a strict, typed, pure functional language. This site is
|
||||
served by an urbit written in Hoon.
|
||||
|
||||
We're still developing the documentation; start with the
|
||||
bottom-up tutorial, ["Hoon 101"](hoon/tutorial).
|
||||
If you're interested in learning the fundamentals of Hoon from
|
||||
the bottom up, start with [Principles of
|
||||
Hoon](hoon/tutorial).
|
||||
|
||||
If you want to jump into building things right away and prefer to
|
||||
learn from the top down, check out [Leap into
|
||||
Hoon](hoon/jump-in/1-basic).
|
||||
|
||||
Both of these are under active development.
|
||||
|
||||
</div>
|
||||
|
420
pub/docs/dev/hoon/leap-in/1-basic.mdy
Normal file
420
pub/docs/dev/hoon/leap-in/1-basic.mdy
Normal file
@ -0,0 +1,420 @@
|
||||
---
|
||||
logo: black
|
||||
sort: 1
|
||||
title: Basic Hoon
|
||||
---
|
||||
|
||||
# Basic Hoon
|
||||
|
||||
Our goal is to get you programming interesting and useful things
|
||||
as soon as possible. To get there we have to quickly cover some
|
||||
of the fundamentals of hoon. To do this we'll walk through two
|
||||
simple programs: the first [Project
|
||||
Euler](https://projecteuler.net/) problem and
|
||||
[fizzbuzz](https://en.wikipedia.org/wiki/Fizz_buzz).
|
||||
|
||||
To run this code, you'll need an urbit, and you'll need the
|
||||
`%examples` desk from `~wactex-ribmex`. If you haven't installed
|
||||
urbit yet, check out the [installation
|
||||
instructions](http://urbit.org/docs/user/install). Once urbit is
|
||||
intalled, take a look at the [basic
|
||||
operation](http://urbit.org/docs/user/basic) of your urbit.
|
||||
|
||||
If you haven't pulled the examples desk from `~wactex-ribmex`, do
|
||||
so now:
|
||||
|
||||
~fintud-macrep:dojo> |merge %examples ~wactex-ribmex %examples
|
||||
>=
|
||||
; ~wactex-ribmex is your neighbor
|
||||
; ~wactex-ribmex is your neighbor
|
||||
[time passes...]
|
||||
merged with strategy %init
|
||||
|
||||
The merge could take several minutes; you'll know it's done when
|
||||
"merged with strategy %init" is printed. Mount the new files to
|
||||
your Unix pier directory:
|
||||
|
||||
~fintud-macrep:dojo> |mount /=examples=
|
||||
|
||||
Switch desks to run commands from the `%examples` desk:
|
||||
|
||||
~fintud-macrep:dojo> =dir /=examples
|
||||
=% /~fintud-macrep/examples/~2015.11.13..02.25.00..41e9/
|
||||
|
||||
Run an example:
|
||||
|
||||
~fintud-macrep:dojo> +euler1
|
||||
233.168
|
||||
|
||||
## Euler 1
|
||||
|
||||
Let's check out the code for Euler 1. First, the problem:
|
||||
|
||||
```
|
||||
If we list all the natural numbers below 10 that are multiples of
|
||||
3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
|
||||
|
||||
Find the sum of all the multiples of 3 or 5 below 1000.
|
||||
```
|
||||
|
||||
Here is the hoon solution (which should be in your pier directory
|
||||
under `/examples/gen/euler1.hoon`):
|
||||
|
||||
```
|
||||
:: project euler 1
|
||||
:: https://projecteuler.net/problem=1
|
||||
:: run in dojo with +euler1
|
||||
::
|
||||
:::: /hoon/euler1/gen
|
||||
::
|
||||
:- %say |= *
|
||||
:- %noun
|
||||
=< (sum 1.000)
|
||||
::
|
||||
:::: ~fintud-macrep
|
||||
::
|
||||
|%
|
||||
++ three
|
||||
|= a=@
|
||||
=| b=@
|
||||
|- ^- @u
|
||||
?: (lth a b)
|
||||
0
|
||||
(add b $(b (add 3 b)))
|
||||
|
||||
++ five
|
||||
|= a=@
|
||||
=| b=@
|
||||
|- ^- @
|
||||
?: (lte a b)
|
||||
0
|
||||
?: =((mod b 3) 0)
|
||||
$(b (add b 5))
|
||||
(add b $(b (add b 5)))
|
||||
|
||||
++ sum
|
||||
|= a=@u
|
||||
(add (five a) (three a))
|
||||
--
|
||||
```
|
||||
|
||||
> Hoon is not generally whitespace sensitive, but we do have two
|
||||
> different kinds of whitespace: a single space and a gap, which
|
||||
> is two or more spaces or a linebreak. Tabs are taboo. Do not
|
||||
> use them. Really. For a more detailed explanation of when to
|
||||
> use spaces vs. gaps, see the syntax section before the first
|
||||
> excercises.
|
||||
|
||||
### Lines 1-11:
|
||||
|
||||
Any line that begins with `::` is a comment.
|
||||
|
||||
:- %say |= *
|
||||
:- %noun
|
||||
=< (sum 1.000)
|
||||
|
||||
All you need to know about the lines above is that they call the
|
||||
`++sum` function with an argument of `1.000`. We'll cover them in
|
||||
more detail later.
|
||||
|
||||
### How to form expressions
|
||||
|
||||
Hoon does not use reserved words to form expressions. Instead,
|
||||
expressions are formed with runes, which are diagraphs of two
|
||||
ascii symbols. Each rune takes a specific number of
|
||||
children--either expressions formed by other runes or literals
|
||||
that produce their own value.
|
||||
|
||||
For example, the rune `?:` from line 17 is the classic
|
||||
'if-then-else' statement, and thus takes three children:
|
||||
|
||||
?: (lth a b) :: if first child evals to true
|
||||
0 :: then produce result of second
|
||||
(add b $(b (add 3 b))) :: else, produce result of third
|
||||
|
||||
Since runes are such a fundamental structure in Hoon, we found
|
||||
ourselves speaking them out loud frequently. It quickly grew
|
||||
cumbersome to have to say "question mark, colon" to describe
|
||||
`?:`. To alleviate this problem, we came up with our own naming
|
||||
scheme: each ascii glyph has a single syllable pronunciation
|
||||
phonetically designed to be both easily remembered and easily
|
||||
pronounced in conjunction with the other glyphs (when forming a
|
||||
rune).
|
||||
|
||||
See the entire naming schema below/or link to it:
|
||||
|
||||
```
|
||||
ace [1 space] gal < pel (
|
||||
bar | gap [>1 space, nl] per )
|
||||
bas \ gar > sel [
|
||||
buc $ hax # sem ;
|
||||
cab _ hep - ser ]
|
||||
cen % kel { soq '
|
||||
col : ker } tar *
|
||||
com , ket ^ tec `
|
||||
doq " lus + tis =
|
||||
dot . pam & wut ?
|
||||
fas / pat @ zap !
|
||||
```
|
||||
|
||||
Using our naming scheme `?:` is said 'wut col'.
|
||||
|
||||
### Lines 12-34
|
||||
|
||||
Now let's quickly walk through this code line-by-line. Lines
|
||||
12-34 are wrapped in a `|%` (pronounced 'bar cen'), which
|
||||
produces a core, a fundamental datatype in hoon similar to a
|
||||
struct, class, or object. A core is just a map of names
|
||||
to any kind of code, whether it be functions or data. Each
|
||||
element in this map begins with a `++` followed by the name and
|
||||
the corresponding code. Since `|%` takes an arbitrary number of
|
||||
children, it needs to be closed with a `--`.
|
||||
|
||||
> `++` is not technically a rune, since it is only used in core
|
||||
> syntax as shown above
|
||||
|
||||
Let's step into each of the three arms within our core.
|
||||
|
||||
### `++ sum`
|
||||
|
||||
++ sum
|
||||
|= a=@
|
||||
(add (five a) (three a))
|
||||
--
|
||||
|
||||
`|=` produces a function, much like a lambda in lisp. It takes two children:
|
||||
|
||||
- A set of argument(s). In this case our argument set only
|
||||
contains one: `a` which is required to be an atom or natural
|
||||
number, denoted by `@`.
|
||||
|
||||
- The body of the function itself, which is executed when the
|
||||
function is called (in this case, with `(sum 1.000)`). This
|
||||
particular function adds the results of evaluating the gates `++
|
||||
five` and `++three` with each of their respective input
|
||||
parameters set to `a`.
|
||||
|
||||
### ++ three
|
||||
|
||||
++ three
|
||||
|= a=@
|
||||
=| b=@
|
||||
|- ^- @u
|
||||
?: (lth a b)
|
||||
0
|
||||
(add b $(b (add 3 b)))
|
||||
|
||||
As above, `++three` takes an integer argument, `a`, and then
|
||||
executes the remainder of the code with `a` set to the actual
|
||||
arguments.
|
||||
|
||||
Similarly, `=|` pushes its first child, `b` into our context (in
|
||||
other words, it declares a variable `b`) and executes the
|
||||
remainder of the code. However, `b` is not an argument; `=|`
|
||||
sets `b` to the default value of whatever type it is declared as.
|
||||
Since the default value of an atom is `0`, b is set to `0`.
|
||||
|
||||
So now we have two variables: `a` is set to our input, and `b` is
|
||||
initialized to `0`.
|
||||
|
||||
The easiest way to think about `|-` that it lays down a recursion
|
||||
point. More on this later.
|
||||
|
||||
`^-` is just a cast that sets the result of the remainder of the
|
||||
code to an unsigned integer, `@u`.
|
||||
|
||||
In pseudocode, the last three lines read like this: if `a` is
|
||||
less than `b`, produce zero. Else, add `b` to the result of
|
||||
rerunning the segment of the function following the `|-` with the
|
||||
value of `b` changed to `b` plus three.
|
||||
|
||||
The only thing that should look completely unfamiliar to you here
|
||||
is the `$(b (add 3 b))`, which causes us to recurse back to our
|
||||
last recursion point with the value of `b` set to `(add 3 b)`.
|
||||
Note that we only specify what changes (`b` in this case). If
|
||||
you recurse by an actual function call, then you have to specify
|
||||
every argument.
|
||||
|
||||
> If you're familiar with Clojure, `|-` is `loop` and `$()` is
|
||||
> recur.
|
||||
|
||||
|
||||
## Excercises
|
||||
|
||||
Please tweak your code to complete the following excercises.
|
||||
|
||||
There are a few runes and some syntax that we have yet to cover that
|
||||
you will need to complete the excercises below. For these, please
|
||||
refer to our cheatsheat at the bottom.
|
||||
|
||||
1. Read and understand `++five` line by line.
|
||||
|
||||
2. Change `++sum` to accept two variables, `a` and `b`. Pass `a`
|
||||
to three and `b` to five. Then run the code with `a` set to
|
||||
`1.000` and b set to `2.000`.
|
||||
|
||||
3. Check if this new result is under one thousand. If it is,
|
||||
return the string 'result is less than one thousand'. If not,
|
||||
return 'result is greater than or equal to one thousand'.
|
||||
|
||||
```
|
||||
Review
|
||||
|
||||
|% start core (collection of named ++ arms)
|
||||
|= define function
|
||||
=| define variable from type with default value
|
||||
|- drop a recursion point
|
||||
^- cast
|
||||
?: if-then-else
|
||||
=(a b) test equality
|
||||
(function args ...) call function
|
||||
|
||||
New material
|
||||
|
||||
- :- make a cell of values. The irregular wide form of this is
|
||||
[a b] with two expressions separated by a single space.
|
||||
|
||||
- Cords are one datatype for text in hoon. They're just a big
|
||||
atom formed from adjacent unicode bytes -- a "c string". To
|
||||
produce a cord enclose text within single quotes. To set the type
|
||||
of an argument to a cord, use @t.
|
||||
|
||||
- There are two syntaxes for writing Hoon: tall form and wide
|
||||
form.
|
||||
|
||||
In tall form, expressions are formed with either two spaces or
|
||||
a line break separating both a rune from its children and each
|
||||
of its children from one another. We use tall form when writing
|
||||
multiline expressions.
|
||||
|
||||
For more concise expressions, we use wideform, which is always
|
||||
a single line. Wideform can be used inside tall form
|
||||
expressions, but not vice versa.
|
||||
|
||||
Wideform expressions are formed with a rune followed by ()
|
||||
containing its children, all of which are separated by a
|
||||
single space. For example to make a cell of two elements:
|
||||
|
||||
:-(a b)
|
||||
|
||||
We've already seen wideform in action, for example with
|
||||
=((mod b 3) 0). In this case = is actually an irregular form
|
||||
of .=, which tests its two children for equality.
|
||||
|
||||
Another irregular form is [a b] for :-(a b)
|
||||
|
||||
Surrounding a function with () is an irregular wide form
|
||||
syntax for calling a function with n arguments.
|
||||
```
|
||||
|
||||
|
||||
## The subject
|
||||
|
||||
Now we're going to cover the boiler plate that we skimmed over
|
||||
earlier.
|
||||
|
||||
:- %say |= *
|
||||
:- %noun
|
||||
=< (sum [1.000 2.000])
|
||||
|
||||
This program is a cell of two elements: the first, `%say`, tells
|
||||
the interpreter what to produce--in this case a value.
|
||||
|
||||
The second element is `|=`, which we know produces a function.
|
||||
`|=`'s first child is its argument(s), which in this case is any
|
||||
noun (`*`). Its second child is the remainder of the program.
|
||||
|
||||
Similarly, the rest of the program is a cell of the literal
|
||||
`%noun`, which tells the shell that we're producing a value of
|
||||
type `noun`, and the second child contains the code that we run
|
||||
to actually produce our value of the type `noun`.
|
||||
|
||||
`=<` is a rune that takes two children. The second child is the
|
||||
context against which we run the first child. So in this case, we
|
||||
are running the expression `(sum 1.000)` against everything
|
||||
contained within the `|%`. In Hoon, we call the code executed the
|
||||
"formula" and its context the "subject".
|
||||
|
||||
```
|
||||
::::::::::::::::::::::::::::::
|
||||
=< (sum 1.000) :: formula
|
||||
::::::::::::::::::::::::::::::
|
||||
|% ::
|
||||
++ three ::
|
||||
|= a=@ ::
|
||||
=| b=@ ::
|
||||
|- ^- @u ::
|
||||
?: (lth a b) ::
|
||||
0 ::
|
||||
(add b $(b (add 3 b))) ::
|
||||
::
|
||||
++ five ::
|
||||
|= a=@ :: subject
|
||||
=| b=@ ::
|
||||
|- ^- @ ::
|
||||
?: (lte a b) ::
|
||||
0 ::
|
||||
?: =((mod b 3) 0) ::
|
||||
$(b (add b 5)) ::
|
||||
(add b $(b (add b 5))) ::
|
||||
::
|
||||
++ sum ::
|
||||
|= a=@u ::
|
||||
(add (five a) (three a)) ::
|
||||
-- ::
|
||||
::::::::::::::::::::::::::::::
|
||||
```
|
||||
|
||||
In nearly every language there is a similar concept of a
|
||||
"context" in which expressions are executed. For example, in C
|
||||
this includes things like the call stack, stack variables, and so
|
||||
on.
|
||||
|
||||
Hoon is unique in that this context is a first-class value.
|
||||
Scheme allows a sort of reification of the context through
|
||||
continutations, and some may see a parallel to Forth's stack, but
|
||||
Hoon takes takes the concept one step further.
|
||||
|
||||
Our starting subject is the standard library, which is defined in
|
||||
`/arvo/hoon.hoon` and `/arvo/zuse.hoon`. This is where functions
|
||||
like `add` are defined. When we define a core with `|%`, we
|
||||
don't throw away the subject (i.e. the standard library); rather,
|
||||
we stack the new core on top of the old subject so that both are
|
||||
accessible.
|
||||
|
||||
## Exercises:
|
||||
|
||||
4. Pass `++sum` its arguments (`2000` and `3000`) from the
|
||||
commandline.
|
||||
|
||||
5. Comment out all of the arms of the `|%`. Now add another arm
|
||||
and call it `++add`, have it accept two arguments and procduce
|
||||
42 (regardless of input). Change the `=<` line to `[(add 5 7)
|
||||
(^add 5 7)]`. Can you recognize what's happening?
|
||||
|
||||
6. Write fizbuzz:
|
||||
|
||||
Write a program that prints the numbers from 1 to 100
|
||||
(entered from the command line). But for multiples of three
|
||||
print 'Fizz' instead of the number and for the multiples of
|
||||
five print 'Buzz'. For numbers which are multiples of both
|
||||
three and five print 'FizzBuzz'.
|
||||
|
||||
Cheatsheet:
|
||||
|
||||
- To pass arguments from the command line to a program, you
|
||||
replace the `*` in the first line of the boiler plate to
|
||||
`[^ [[arg=TYPE ~] ~]]` where `TYPE` is replaced with the
|
||||
type of argument you're expecting. Then `+euler1 a` from
|
||||
the dojo sets `arg` to `a`.
|
||||
- A list of strings is of type `(list ,@t)`, so the result of
|
||||
the fizzbuzz function is of this type (hint: you'll need to
|
||||
use `^-`)
|
||||
- The empty list is `~`
|
||||
- Lisp-style cons (construct a cell/prepend an element) is
|
||||
`[new-element list]`
|
||||
- For example, the first three positive integers are `[1 2 3
|
||||
~]`
|
||||
- `gte` tests whether `a` is greater than or equal to `b`.
|
||||
- `mod` runs the modulo operation on two atoms.
|
||||
- See the [basic math section]() for more info.
|
188
pub/docs/dev/hoon/leap-in/2-network.mdy
Normal file
188
pub/docs/dev/hoon/leap-in/2-network.mdy
Normal file
@ -0,0 +1,188 @@
|
||||
---
|
||||
hide: true
|
||||
next: false
|
||||
sort: 3
|
||||
title: Network Messages
|
||||
---
|
||||
|
||||
Enough of pure hoonery. Let's get to the good stuff. Let's get
|
||||
our planets to talk to each other.
|
||||
|
||||
Of course, for talking to be of any use, we need someone
|
||||
listening. What we've written up until now are just shell
|
||||
commands that produce a value and then disappear. We need an
|
||||
actual app to listen for messages from another planet. Let's
|
||||
take a look at a very basic one.
|
||||
|
||||
```
|
||||
:: There is no love that is not an echo
|
||||
::
|
||||
:::: /hoon/echo/ape
|
||||
::
|
||||
/? 314
|
||||
|%
|
||||
++ move ,*
|
||||
--
|
||||
!:
|
||||
|_ [bowl state=~]
|
||||
++ poke-noun
|
||||
|= arg=*
|
||||
^- [(list move) _+>.$]
|
||||
~& [%argument arg]
|
||||
[~ +>.$]
|
||||
--
|
||||
```
|
||||
|
||||
This is a very simple app that does only one thing. If you poke
|
||||
it with a value it prints that out. You have to start the app,
|
||||
then you can poke it from the command line.
|
||||
|
||||
```
|
||||
> |start %echo
|
||||
>=
|
||||
> :echo 5
|
||||
[%argument 5]
|
||||
> :echo [1 2]
|
||||
[%argument [1 2]]
|
||||
```
|
||||
|
||||
Most of the app code should be simple enough to guess its
|
||||
function. The important part of this code is the definition of
|
||||
`++poke-noun`.
|
||||
|
||||
Once an app starts, it's always on in the background, and you
|
||||
interact with it by sending it messages. The most
|
||||
straightforward way to do that is to poke it from the command
|
||||
line. When you do that, `++poke-noun` is called from your app.
|
||||
|
||||
In our case, `++poke-noun` takes an argument `arg` and prints it
|
||||
out with `~&`. This is an unusual rune that formally "does
|
||||
nothing", but the interpreter detects it and printfs the first
|
||||
child. This is a slightly hacky way of printing to the console,
|
||||
and we'll get to the correct way later on.
|
||||
|
||||
But what does `++poke-noun` produce? The phrase to remember is
|
||||
"a list of moves and our state". Urbit is a message passing
|
||||
system, so whenver we want to do something that interacts with
|
||||
the rest of the system we send a message. Thus, the first thing
|
||||
that `++poke-noun` produces is a list of messages, called
|
||||
"moves". In this case, we don't actually want the system to do
|
||||
anything, so we produce the empty list, `~`.
|
||||
|
||||
The second thing `++poke-noun` produces is our state. `+>.$`
|
||||
refers to a particular address in our subject where our formal
|
||||
app state is stored. It'll become clear why this is later on,
|
||||
but for now pretend that `+>.$` is a magic invocation that means
|
||||
"app state".
|
||||
|
||||
---
|
||||
|
||||
But what is our app state, exactly? In Unix systems, application
|
||||
state is just a block of memory, which you need to serialize to
|
||||
disk if you want to keep it around for very long.
|
||||
|
||||
In urbit, app state is a single (usually complex) value. In our
|
||||
example, we don't have any special state, so we defined
|
||||
`state=~`, meaning that our state is null. Of course, `state` is
|
||||
just a name we're assigning to it, and you're free to use
|
||||
whatever name you want.
|
||||
|
||||
Since urbit is purely functional, we can't just implicitly "have"
|
||||
and "change" our state. Rather, it's explicitly passed to us, in
|
||||
the `|_ [bowl state=~]` line, and we produce the new state with
|
||||
`+>.$` in the `[~ +>.$]` line.
|
||||
|
||||
Two points you may be wondering about. Firstly, `bowl` is a set
|
||||
of general global state that is managed by the system. It
|
||||
includes things like `now` (current time), `our` (our urbit
|
||||
identity), and `eny` (256 bits of guaranteed-fresh entropy). For
|
||||
the full list of things in `++bowl`, search for `++ bowl` (note
|
||||
the double space) in `/arvo/zuse.hoon`.
|
||||
|
||||
> This is a very common technique in learning hoon. While some
|
||||
> documentation exists, often the easiest way to learn about an
|
||||
> identifier you see in code is to search in `/arvo/zuse.hoon`
|
||||
> and `/arvo/hoon.hoon` for it. These are our two "standard
|
||||
> libraries", and they're usually not hard to read. Since
|
||||
> urbit's codebase is relatively small (those two files are less
|
||||
> than 15000 lines of code combined, and besides the standard
|
||||
> library they include the hoon parser and compiler, plus the
|
||||
> /arvo microkernel), you can usually use the code and the
|
||||
> comments as reference doc.
|
||||
|
||||
Second point is that urbit needs no "serialize to disk" step.
|
||||
Everything you produce in the app state is persistent across
|
||||
calls to the app, restarts of the urbit, and even power failure.
|
||||
If you want to write to the filesystem, you can, but it's not
|
||||
needed for persistence. Urbit has transactional events, which
|
||||
makes it an ACID operating system. Persistence is just another
|
||||
one of those things you don't have to worry about when
|
||||
programming in urbit.
|
||||
|
||||
As fascinating as state is, we don't actually need any state to
|
||||
accomplish our immediate goal, which is to get apps on two urbits
|
||||
talking to each other. We'll discuss state more in a later
|
||||
chapter.
|
||||
|
||||
---
|
||||
|
||||
Anyway, that's a lot of theory, let's get back to coding. Let's
|
||||
say we want to only accept a number, and then print out the
|
||||
square of that number.
|
||||
|
||||
```
|
||||
/? 314
|
||||
|%
|
||||
++ move ,*
|
||||
--
|
||||
!:
|
||||
|_ [bowl state=~]
|
||||
::
|
||||
++ poke-atom
|
||||
|= arg=@
|
||||
^- [(list move) _+>.$]
|
||||
~& [%square (mul arg arg)]
|
||||
[~ +>.$]
|
||||
--
|
||||
```
|
||||
|
||||
A few things have changed. Firstly, we no longer accept
|
||||
arbitrary nouns because we can only square atoms. Thus, our
|
||||
argument is now `arg=@`. Secondly, it's `++poke-atom` rather
|
||||
than `++poke-noun`.
|
||||
|
||||
Are there other `++poke`s? Definitely. In fact, `noun` and
|
||||
`atom` are just two of arbitrarily many "marks". A mark is
|
||||
fundamentally a type definition, and each mark is defined in the
|
||||
`/mar` directory. Some marks have conversion routines to other
|
||||
marks, and some have diff, path, and merge algorithms. None of
|
||||
these are required for a mark to exist, though.
|
||||
|
||||
`noun` and `atom` are two of dozens of predefined marks, and the
|
||||
user may add more at will. The type associated with `noun` is
|
||||
`*`, and the type associated with `atom` is `@`.
|
||||
|
||||
Data constructed on the command line is by default marked with
|
||||
`noun`. In this case, the app is expecting an atom, so we have
|
||||
to explicitly mark the data with `atom`.
|
||||
|
||||
```
|
||||
> |start %square
|
||||
> :square 6
|
||||
gall: %square: no poke arm for noun
|
||||
> :square &atom 6
|
||||
[%square 36]
|
||||
```
|
||||
|
||||
Marks are powerful, and they're the backbone of urbit's data
|
||||
pipeline, so we'll be getting quite used to them.
|
||||
|
||||
Let's write our first network message!
|
||||
|
||||
-don't forget to explain new hoon concepts ([])
|
||||
-excercises
|
||||
-then walk through more in depth
|
||||
-move app state section to somewhere later
|
||||
-put in interactive code snippets and explain a lil (bowl)
|
||||
|
||||
|
@ -281,6 +281,6 @@ Can we use mutation to build a cyclical noun? Nice try, but no:
|
||||
|
||||
## Progress
|
||||
|
||||
Now, not only can we build a noun, we can get data out of it and
|
||||
Now, not only can you build a noun, you can get data out of it and
|
||||
even evolve new, related nouns. We've still seen only two very
|
||||
restricted kinds of twigs: constants and legs. In the [next chapter](2-syntax), we'll actually write some interesting expressions.
|
@ -244,6 +244,16 @@ ever. In Hoon it's called a *kelp*.
|
||||
The head of a kelp (like `%dtzy` above) is called the *stem*.
|
||||
The tail (like `[%ux 42]`) is the *bulb*.
|
||||
|
||||
> Think about how to encode tagged data in a noun. It seems
|
||||
obvious that the noun is a cell, where the head of the cell is
|
||||
the tag (stem) and the tail is the data (bulb). Then, all these
|
||||
nouns are cells whose head is an atom. This leaves two noun
|
||||
shapes "out of band": atoms, and cells whose head is a cell.
|
||||
|
||||
> Since no twig is an atom, a cell `[twig twig]` is always a cell
|
||||
whose head is a cell. So we can distinguish "autocons" from all
|
||||
stem-bulb nouns, and assign it specific semantics.
|
||||
|
||||
#### Runes and stems
|
||||
|
||||
A *rune* is a digraph - a sequence of two ASCII glyphs. If you
|
||||
@ -359,7 +369,7 @@ there are no fixed rules for doing it right.
|
||||
> Keep lines under 80 characters, though. The parser doesn't
|
||||
enforce this yet. But it will, so watch out!
|
||||
|
||||
##### Backstep indentation
|
||||
#### Backstep indentation
|
||||
|
||||
Note that the "variable declaration" metaphor of `=+` works
|
||||
perfectly here. Because `[%hello planet]` -- despite being a
|
||||
@ -462,4 +472,4 @@ Or with a gratuitous use of tall form:
|
||||
Now you know how to read Hoon! For fun, try to pronounce more of
|
||||
the code on this page. Please don't laugh too hard at yourself.
|
||||
|
||||
In the next chapter, we'll actually write a real program...
|
||||
In the [next chapter](3-program), we'll actually write a real program...
|
350
pub/docs/dev/hoon/principles/3-program.mdy
Normal file
350
pub/docs/dev/hoon/principles/3-program.mdy
Normal file
@ -0,0 +1,350 @@
|
||||
---
|
||||
title: Hoon 101.3: an algorithm
|
||||
sort: 3
|
||||
hide: true
|
||||
next: false
|
||||
---
|
||||
# Hoon 101.3: an algorithm
|
||||
|
||||
In [chapter 0](0-nouns), we read about nouns. In [chapter 1](1-twigs),
|
||||
we discovered twigs and legs. In [chapter 2](2-syntax), we learned
|
||||
Hoon syntax and created our first source file.
|
||||
|
||||
Now it's time for an actual, meaningful *algorithm*.
|
||||
|
||||
## How to use this tutorial
|
||||
|
||||
Ideally, you've installed an Urbit planet (if you have a ticket)
|
||||
or comet (if you don't). See the [user doc](../../../user).
|
||||
|
||||
We recommend opening up the dojo and just typing the examples;
|
||||
you don't know a language until you know it in your fingers.
|
||||
Also, make sure you've worked through the chapters in order.
|
||||
|
||||
## Goal: a decrement generator
|
||||
|
||||
Our algorithm is the classic Urbit example: decrement.
|
||||
|
||||
If you learned [Nock](../../nock) before Hoon, you've already
|
||||
written decrement. If not, all you need to know is that the only
|
||||
built-in arithmetic operator in Nock is increment. To decrement,
|
||||
we need to count up to the result with a simple loop.
|
||||
|
||||
## A practical subject
|
||||
|
||||
As we've seen, Hoon works by running a twig against a subject.
|
||||
In chapter 1, we made a simple test subject that was just a few
|
||||
constants, and applied some simple twigs to it.
|
||||
|
||||
This time, we'll actually put useful working data in the subject,
|
||||
building up more and more complex subjects as we go.
|
||||
|
||||
## Subject: nil
|
||||
|
||||
We'll start with the empty subject `~`:
|
||||
```
|
||||
:- %say |= * :- %noun
|
||||
=> ~
|
||||
[%hello %world]
|
||||
```
|
||||
The `=>` rune ("tisgar", `%tsgr`)), for `=>(p q)` executes `p`
|
||||
against the subject, then uses that product as the subject of
|
||||
`q`.
|
||||
|
||||
> We've already used an irregular form of `=>`, or to be more
|
||||
precise its mirror `=<` ("tisgal", `%tsgl`). In chapter 1, when we wrote
|
||||
`+3:test`, we meant `=>(test +3)` or `=<(+3 test)`.
|
||||
|
||||
What is `~`? It's Hoon `nil`, a zero atom:
|
||||
```
|
||||
~tasfyn-partyv:dojo/sandbox> ?? ~
|
||||
[%cube 0 [%atom %n]]
|
||||
~
|
||||
```
|
||||
We use `~` for list terminators and the like. Obviously, since
|
||||
`[%hello %world]` is just a constant, a nil subject works as
|
||||
well as any:
|
||||
|
||||
```
|
||||
~tasfyn-partyv:dojo/sandbox> +test
|
||||
[%hello %world]
|
||||
```
|
||||
|
||||
## Subject: `arg=@`
|
||||
|
||||
Above, we used an empty subject to avoid the very complex,
|
||||
interesting subject your generator twig gets by default.
|
||||
|
||||
But a decrement generator needs to get an argument from the
|
||||
command line -- the number we're trying to decrement.
|
||||
|
||||
This involves changing the `test.hoon` boilerplate a little.
|
||||
Again, don't worry about the boilerplate line just yet:
|
||||
```
|
||||
:- %say |= [* [[arg=@ud ~] ~]] :- %noun
|
||||
=> arg=arg
|
||||
[%hello arg]
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
[%hello 42]
|
||||
```
|
||||
> `=> arg=arg` looks a little odd. We wouldn't ordinarily do
|
||||
this; we're just trying to keep the subject simple.
|
||||
|
||||
In case there's any doubt about the subject (remember from
|
||||
chapter 1 that `.` means `+1`, the whole subject):
|
||||
```
|
||||
:- %say |= [* [[arg=@ud ~] ~]] :- %noun
|
||||
=> arg=arg
|
||||
.
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
arg=42
|
||||
```
|
||||
|
||||
## An increment generator
|
||||
|
||||
We can even write a trivial increment generator using `.+`,
|
||||
or even better its irregular form `+`:
|
||||
```
|
||||
:- %say |= [* [[arg=@ud ~] ~]] :- %noun
|
||||
=> arg=arg
|
||||
+(arg)
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
43
|
||||
```
|
||||
We'll assume these same first two lines for the rest of the
|
||||
examples in this chapter.
|
||||
|
||||
## Cores: one more kind of span
|
||||
|
||||
To decrement, we need a loop. To write a loop, we need yet
|
||||
another kind of noun: the *core*. Briefly, a core is a `[code
|
||||
data]` pair. Our new `span` mold:
|
||||
```
|
||||
++ span
|
||||
$% [%atom p=@tas]
|
||||
[%cell p=span p=span]
|
||||
[%core p=span q=(map ,@tas twig)]
|
||||
[%cube p=* q=span]
|
||||
[%face p=@tas q=span]
|
||||
==
|
||||
```
|
||||
|
||||
### Structure of a core
|
||||
|
||||
The core is a cell `[battery payload]`. The payload is data, the
|
||||
battery is code -- a tree of Nock formulas.
|
||||
|
||||
In the `%core` span, the payload is described by an arbitrary
|
||||
span. The battery is described by a map of symbol to twig.
|
||||
|
||||
> Yes, the span contains the complete AST of the whole core.
|
||||
This is a very different approach from most typed languages,
|
||||
which compute function signatures. To infer the product of an
|
||||
arm, we retrace the code in theory, but cache in practice.
|
||||
|
||||
### Arms are computed attributes
|
||||
|
||||
How do we use a core? Remember that Nock is a function
|
||||
```
|
||||
Nock(subject formula) -> product
|
||||
```
|
||||
To activate a core, we pull one formula from the battery, and
|
||||
execute with the whole core as the subject. Coincidentally,
|
||||
Nock has one macro instruction, `9`, that does just this.
|
||||
|
||||
So the formula defines an arbitrary function on the core. The
|
||||
name of this function (as defined in the twig map) is a computed
|
||||
attribute, or *arm*.
|
||||
|
||||
> Is a core an object? Not quite, because an arm is not a method.
|
||||
Methods in an OO language have arguments. Arms are functions
|
||||
only of the payload. (A method in Hoon is an arm that produces a
|
||||
gate, which is another core -- but we're getting too far ahead.)
|
||||
However, the battery does look a lot like a classic "vtable."
|
||||
|
||||
### Arms and wing resolution
|
||||
|
||||
It might be a good time to brush up on your [chapter 1](1-twigs).
|
||||
The wing resolution algorithm gets a little more complicated.
|
||||
|
||||
Hoon overloads computed attributes (arms) and literal attributes
|
||||
(legs) in the same namespace. A label in a wing may refer to
|
||||
either. when searching a core, we look for a matching arm. If
|
||||
we find it we're done. If we don't, or if a `^` mark makes us
|
||||
skip, we search into the payload.
|
||||
|
||||
Only the last limb in the wing can activate an arm. If a name
|
||||
resolves to a core arm, but it's not the last limb in the wing,
|
||||
the arm produces the core itself. Similarly, when the wing is
|
||||
not an access but a mutation, the arm refers to the core. Only
|
||||
the end of the wing is activated.
|
||||
|
||||
> Suppose `foo` is a core. `bar` is an arm on foo. Then `bar.foo`
|
||||
computes the `bar` arm. Perhaps the product is another core.
|
||||
Even if `moo` is an arm in this new core, `bar.foo`, the wing
|
||||
`moo.bar.foo` does not compute `moo` on the core `bar.foo`.
|
||||
Instead, it looks for `moo` within the payload of the core `foo`.
|
||||
(You're looking for `moo:bar.foo`, ie, `=>(bar.foo moo)`.)
|
||||
|
||||
Does this sound too tricky? Hopefully not, but it's about the
|
||||
most complicated semantic rule you'll find in Hoon.
|
||||
|
||||
## Increment with a core
|
||||
|
||||
Keeping our two-line boilerplate, let's increment with a core:
|
||||
```
|
||||
=< inc
|
||||
|%
|
||||
++ inc
|
||||
+(arg)
|
||||
--
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
43
|
||||
```
|
||||
What's going on? We used the `|%` rune ("barcen") to produce a
|
||||
core. (There are a lot of runes which create cores; they all
|
||||
start with `|`, and are basically macros that turn into `|%`.)
|
||||
|
||||
The payload of a core produced with `|%` is the subject with
|
||||
which `|%` is compiled. We might say that `|%` wraps a core
|
||||
around its subject. In this case, the subject of the `|%`,
|
||||
and thus payload, is our `arg=@ud` argument.
|
||||
|
||||
Then we used this core as the subject of the simple wing `inc`.
|
||||
|
||||
> Remember that `=<(a b)` is just `=>(b a)`. The core is heavy
|
||||
and `inc` is light, so we use `=<` to put the heavy part last.
|
||||
|
||||
The prettyprinter can even print a core, sort of. Take out the
|
||||
`=< inc`:
|
||||
```
|
||||
|%
|
||||
++ inc
|
||||
+(arg)
|
||||
--
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
<1.bgq arg=42>
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> ? +test 42
|
||||
<1.bgq arg=@ud>
|
||||
<1.bgq arg=42>
|
||||
```
|
||||
In this notation, `1` means the number of arms in the core, `bgq`
|
||||
is a very short fingerprint, and `arg=42` is the payload (and
|
||||
`arg=@ud` is the payload span).
|
||||
|
||||
> Cores can be large and complex, and we obviously can't render all
|
||||
the data in them, either when printing a type or a value. At
|
||||
some point, you'll probably make the mistake of printing a big
|
||||
core, maybe even the whole kernel, as an untyped noun. Just
|
||||
press ^C.
|
||||
|
||||
## Adding a counter
|
||||
|
||||
To decrement, we need to count up to the argument. So we need a
|
||||
counter in our subject, because where else would it go?
|
||||
|
||||
Let's change the subject to add a counter, `pre`:
|
||||
```
|
||||
=> [pre=0 .]
|
||||
=< inc
|
||||
|%
|
||||
++ inc
|
||||
+(arg)
|
||||
--
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
43
|
||||
```
|
||||
Once again, `.` is the whole subject, so we're wrapping it in a
|
||||
cell whose head is `pre=0`. This doesn't change the way we use
|
||||
`arg`, even though it's one level deeper in the subject tree.
|
||||
Let's look at the subject again:
|
||||
```
|
||||
=> [pre=0 .]
|
||||
.
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
[pre=0 arg=42]
|
||||
~tasfyn-partyv:dojo/sandbox> ? +test 42
|
||||
[pre=@ud arg=@ud]
|
||||
[pre=0 arg=42]
|
||||
```
|
||||
There's a less cluttered way to write `=>([a .] b)`. In wide
|
||||
mode, `=+(a b)`. A tall example:
|
||||
```
|
||||
=+ pre=0
|
||||
.
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
[pre=0 arg=42]
|
||||
```
|
||||
This rune `=+`, "tislus", `%tsls`, is of course the "variable
|
||||
declaration" we saw in chapter 2.
|
||||
|
||||
## We actually decrement
|
||||
|
||||
Now we can write our actual decrement program, combining the
|
||||
features we've explored above:
|
||||
```
|
||||
=+ pre=0
|
||||
=< dec
|
||||
|%
|
||||
++ dec
|
||||
?: =(arg +(pre))
|
||||
pre
|
||||
dec(pre +(pre))
|
||||
--
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
41
|
||||
```
|
||||
`=(a b)` is an irregular form of `.=(a b)`, ie, "dottis" or the
|
||||
noun `[%dtts a b]`. Likewise, `+(a)` is `.+(a)`, ie, "dotlus"
|
||||
or `[%dtls a]`.
|
||||
|
||||
`?:`, "wuttis", `%wtts`, does exactly what it does in C.
|
||||
|
||||
The real action is in `dec(pre +(pre))`. We saw this same
|
||||
mutation form in chapter 1. It's an irregular form of the `%=`
|
||||
rune, "centis", `%cnts`.
|
||||
|
||||
Here, of course, we're computing an arm of a mutated core. We're
|
||||
recomputing the loop arm, `dec`, against a new core with an
|
||||
incremented `pre` leg. Basically, everything interesting in Hoon
|
||||
happens when you compute an arm of a mutated core.
|
||||
|
||||
The whole program, using only regular forms, wide and tall:
|
||||
```
|
||||
=+ ^=(pre 0)
|
||||
=< dec
|
||||
|%
|
||||
++ dec
|
||||
?: .=(arg .+(pre))
|
||||
pre
|
||||
%= dec
|
||||
pre .+(pre)
|
||||
==
|
||||
--
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
41
|
||||
```
|
||||
A good illustration of why we need irregular forms.
|
||||
|
||||
## Progress
|
||||
|
||||
Now we've actually done something useful. Well, if you count
|
||||
O(n) decrement as something useful.
|
||||
|
||||
We've actually seen most of the major tools in Hoon's toolbox,
|
||||
just in a super-minimalist selection. But we'll need a few more
|
||||
runes to get to something that looks like real programming.
|
||||
|
||||
For instance, we have a decrement algorithm, but we don't have a
|
||||
decrement *function* - in the Hoon sense of the word, anyway. We
|
||||
don't see `(dec arg)` in this code. That'll be the next chapter.
|
327
pub/docs/dev/hoon/principles/4-functions.mdy
Normal file
327
pub/docs/dev/hoon/principles/4-functions.mdy
Normal file
@ -0,0 +1,327 @@
|
||||
---
|
||||
title: Hoon 101.4: functions
|
||||
sort: 4
|
||||
hide: true
|
||||
next: false
|
||||
---
|
||||
# Hoon 4: toward actual functions
|
||||
|
||||
In [chapter 0](0-nouns), we read about nouns. In [chapter 1](1-twigs),
|
||||
we discovered twigs and legs. In [chapter 2](2-syntax), we learned
|
||||
Hoon syntax and created our first source file. In [chapter 3](3-algorithm)
|
||||
we wrote an actual algorithm.
|
||||
|
||||
Now we'll go a step farther and actually define a *function*.
|
||||
|
||||
## Goal: `(decrement arg)`
|
||||
|
||||
Of course, Hoon is a functional language and every twig defines a
|
||||
function of the subject. But we haven't seen the Hoon equivalent
|
||||
of a function *declaration*. Where is Lisp `defun`?
|
||||
|
||||
Also, the Hoon equivalent of a normal function call can't just
|
||||
involve compiling the function into a Nock formula, whose subject
|
||||
is the function's argument. As Einstein said, everything must be
|
||||
as simple as possible, but no simpler.
|
||||
|
||||
A function that worked this way would, by definition, have no
|
||||
access to data or code other than the argument. Where would the
|
||||
standard library go? Would we have to pass it in the argument?
|
||||
|
||||
## Form of the solution
|
||||
|
||||
Let's get the boilerplate out of the way. We'll keep the same
|
||||
external generator interface, but our solution will look like:
|
||||
|
||||
```
|
||||
=< :- %say |= [* [[arg=@ud ~] ~]] :- %noun
|
||||
(decrement arg)
|
||||
=> ~
|
||||
!!
|
||||
```
|
||||
In place of the `!!`, we'll put a core, effectively a library,
|
||||
that exports a function `decrement`. We'll then call that
|
||||
function with `(decrement arg)`, an irregular form of
|
||||
`%-(decrement arg)`. Again, this core uses `=> ~` to clear
|
||||
the subject, so we can't cheat and call `(dec arg)`.
|
||||
|
||||
> `!!`, or "zapzap" or `[%zpzp ~]`, is a twig that
|
||||
always crashes. Because it produces the empty span (`%void`), it
|
||||
doesn't cause type inference problems.
|
||||
|
||||
## Not quite a function call
|
||||
|
||||
As usual, we'll get to our goal gradually. A first try:
|
||||
```
|
||||
=< :- %say |= [* [[arg=@ud ~] ~]] :- %noun
|
||||
=+ gat=decrement
|
||||
=<(run gat(sam arg))
|
||||
=> ~
|
||||
|%
|
||||
++ decrement
|
||||
=+ sam=0
|
||||
=+ pre=0
|
||||
|%
|
||||
++ run
|
||||
?: =(sam +(pre))
|
||||
pre
|
||||
run(pre +(pre))
|
||||
--
|
||||
--
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
41
|
||||
```
|
||||
This works, but it's hardly concise or pretty. We'll get there.
|
||||
|
||||
We replaced the `!!` with a `|%` twig that produces a library
|
||||
core. The payload of our library core is `~`, because that's the
|
||||
subject we sent in. The battery contains one arm, `decrement`.
|
||||
|
||||
The `decrement` arm produces an inner core. The payload of this
|
||||
inner core is `[pre=0 sam=0 +>]`, where `+>` is the library core.
|
||||
The battery of the inner core has one arm, `run`, which computes
|
||||
our algorithm from the last chapter.
|
||||
|
||||
To run our algorithm, we put the core that `decrement` produces
|
||||
into a new leg, `gat`. Mutating this core to set `sam` to our
|
||||
argument `arg`, we evaluate the `run` arm.
|
||||
|
||||
> Why do we need this `gat` leg? Why can't we just write `=<(run
|
||||
decrement(sam arg))`? Remember our `moo:bar.foo` problem from
|
||||
the previous chapter. `decrement(sam arg)` mutates not the
|
||||
*product* of the decrement arm, but the core that computes it.
|
||||
There's no `sam` in that subject, so the twig won't compile.
|
||||
|
||||
## Better is worse
|
||||
|
||||
To make this code look simpler, we need to make it more complex.
|
||||
Our next try uses not two nested cores, but *three*:
|
||||
```
|
||||
=< :- %say |= [* [[arg=@ud ~] ~]] :- %noun
|
||||
=+ gat=decrement
|
||||
=<(run gat(sam arg))
|
||||
=> ~
|
||||
|%
|
||||
++ decrement
|
||||
=+ sam=0
|
||||
|%
|
||||
++ run
|
||||
=+ pre=0
|
||||
=< loop
|
||||
|%
|
||||
++ loop
|
||||
?: =(sam +(pre))
|
||||
pre
|
||||
loop(pre +(pre))
|
||||
--
|
||||
--
|
||||
--
|
||||
```
|
||||
This is actually the final structure of our function, but uses
|
||||
none of the syntactic tricks we'll use to make it pretty.
|
||||
|
||||
> Why do we need to make the code more complex? Because we need
|
||||
it to use the regular form that our synthetic runes, ie macros,
|
||||
use to express function definitions and calls.
|
||||
|
||||
## Loop sugar
|
||||
|
||||
Look at little `loop`. It works just like our old `run`. But
|
||||
there's something nice about it: we don't use the symbol `loop`
|
||||
anywhere outside these 7 lines of code. It's not exported.
|
||||
|
||||
Therefore, the `loop` name is useless and redundant. Making up
|
||||
names is one of the hard problems in computer science, so why
|
||||
solve it for no reason?
|
||||
|
||||
So Hoon has an *empty name*: `$`. As a constant, `$` is a
|
||||
zero-length symbol (`%$` instead of `%foo`) As a limb is the
|
||||
`buc` symbol (`$`).
|
||||
|
||||
Replacing `loop` with `$`, our loop becomes:
|
||||
```
|
||||
=< $
|
||||
|%
|
||||
++ $
|
||||
?: =(sam +(pre))
|
||||
pre
|
||||
$(sam +(run))
|
||||
--
|
||||
```
|
||||
|
||||
This may not seem like a huge improvement. It's not. But it
|
||||
lets us match and move to the synthetic rune `|-`, "barhep":
|
||||
```
|
||||
|- ?: =(sam +(pre))
|
||||
pre
|
||||
$(pre +(pre))
|
||||
```
|
||||
`|-` is simply the canonical Hoon loop. All we've done to use a
|
||||
core as a loop is to name our arm `$`, and evaluate it on the
|
||||
core we just made.
|
||||
|
||||
Our program now:
|
||||
```
|
||||
=< :- %say |= [* [[arg=@ud ~] ~]] :- %noun
|
||||
=+ gat=decrement
|
||||
=<(run gat(sam arg))
|
||||
=> ~
|
||||
|%
|
||||
++ decrement
|
||||
=+ sam=0
|
||||
|%
|
||||
++ run
|
||||
=+ pre=0
|
||||
|- ?: =(sam +(pre))
|
||||
pre
|
||||
$(pre +(pre))
|
||||
--
|
||||
--
|
||||
```
|
||||
|
||||
## Almost to lambda
|
||||
|
||||
Could we use `$` for `++run`? It certainly sounds like the same
|
||||
kind of thing as `++loop`. The word "run" just means "do it".
|
||||
Why should we be saying "do it" all the time?
|
||||
|
||||
Our third try, with this change:
|
||||
```
|
||||
=< :- %say |= [* [[arg=@ud ~] ~]] :- %noun
|
||||
=+ gat=decrement
|
||||
=<($ gat(sam arg))
|
||||
=> ~
|
||||
|%
|
||||
++ decrement
|
||||
=| sam=@ud
|
||||
|%
|
||||
++ $
|
||||
=+ pre=0
|
||||
|- ?: =(sam +(pre))
|
||||
pre
|
||||
$(pre +(pre))
|
||||
--
|
||||
--
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
41
|
||||
```
|
||||
> Besides `run` to `$`, we changed `=+ sam=0` to `=| sam=@ud`.
|
||||
This is some mold magic we'll explain in the next chapter, but
|
||||
it basically does the same thing: pushes a leg named `sam`, whose
|
||||
value is a number we'll later overwrite.
|
||||
|
||||
This use of `$` in a core, very similar to the way we used `$` in
|
||||
our `|-` loop, smells like it too should have a rune. It does:
|
||||
```
|
||||
=< :- %say |= [* [[arg=@ud ~] ~]] :- %noun
|
||||
=+ gat=decrement
|
||||
=<($ gat(sam arg))
|
||||
=> ~
|
||||
|%
|
||||
++ decrement
|
||||
|= sam=@ud
|
||||
=+ pre=0
|
||||
|- ?: =(sam +(pre))
|
||||
pre
|
||||
$(pre +(pre))
|
||||
--
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
41
|
||||
```
|
||||
Doesn't `decrement` look like a function? Indeed, we're done with
|
||||
the `decrement` arm. This is what it should look like.
|
||||
|
||||
> If you squint a little, `|=` ("bartis") might even be a strange,
|
||||
deformed ASCII-art lambda.
|
||||
|
||||
Since it's doing something simple, we might well even compress
|
||||
the whole body of `decrement` into one wide-form line:
|
||||
```
|
||||
=+(pre=0 |-(?:(=(sam +(pre)) pre $(pre +(pre)))))
|
||||
```
|
||||
This is a bit tight for most. But we can get really compact by
|
||||
dropping the labels and going to full geometry:
|
||||
|
||||
```
|
||||
=< :- %say |= [* [[arg=@ud ~] ~]] :- %noun
|
||||
=+ gat=decrement
|
||||
=<($ gat(sam arg))
|
||||
=> ~
|
||||
|%
|
||||
++ decrement |=(@ud =+(0 |-(?:(=(+>+< +<) +< $(+< +(+<))))))
|
||||
--
|
||||
```
|
||||
> It's not a good idea to actually program this way. But it does
|
||||
strengthen your Hoon tree-geometry muscles. To use tree
|
||||
geometry, you have to really know the shape of your subject.
|
||||
|
||||
## Structure of a gate
|
||||
|
||||
What is the noun produced by `decrement`? In true Hoonese it's
|
||||
a *gate*, but nobody will hate you for saying "function." And
|
||||
while we *slam* our gates, you can feel free to just "call" them.
|
||||
|
||||
Every gate is a core; not every core is a gate. All cores are
|
||||
shaped like `[battery payload]`. A core is a gate if its payload
|
||||
is a cell, and its battery has one arm, `$`. So a gate is shaped
|
||||
like `[formula [sample context]]`.
|
||||
|
||||
To slam (call) a gate, you replace its sample (`+6` or `+<`,
|
||||
"lusgal" or "dish") with your argument. "Multiple arguments" are
|
||||
a single sample that's a tuple. So our code should actually read
|
||||
```
|
||||
=+ gat=decrement
|
||||
=<($ gat(+< arg))
|
||||
```
|
||||
This `=+` sequence remains ugly. Once again, `decrement(+< arg)`
|
||||
is not a mutation to the product of `decrement`, but a mutation
|
||||
to the core that produces `decrement`. Fortunately, there's a
|
||||
sugary rune that combines the semantics of both these lines:
|
||||
```
|
||||
%*($ decrement +< arg))
|
||||
```
|
||||
This mutates the product of `decrement` as specified. (`+< arg`
|
||||
in the wide form of `$*` is just the first of n comma-separated
|
||||
pairs; we could write `%*($ decrement +< arg, +> foo, moo 42)`.
|
||||
|
||||
> Arguably, %* is oversweetened; $:(decrement +< arg)
|
||||
would be simpler and better. Hoon isn't perfect.
|
||||
|
||||
## Slamming the gate
|
||||
|
||||
Anyway, it shouldn't come as a surprise that a synonym for
|
||||
`%*($ function +< argument)` is `%-(function argument)`. And an
|
||||
irregular form of this is just `(function argument)`.
|
||||
|
||||
The irregular syntax constructs multiple-argument syntax as a
|
||||
tuple; `(add 2 2)` is `(add [2 2])`, `(rsh 3 1 5)` is `(rsh [3 1 5])`.
|
||||
If there are no arguments, `(function)`, this means `$:function`,
|
||||
ie, `=>(function $)`.
|
||||
|
||||
We can also take the `=> ~` out, since we now know what we're
|
||||
doing. The final program:
|
||||
```
|
||||
=< :- %say |= [* [[arg=@ud ~] ~]] :- %noun
|
||||
(decrement arg)
|
||||
|%
|
||||
++ decrement
|
||||
|= sam=@ud
|
||||
=+ pre=0
|
||||
|- ?: =(sam +(pre))
|
||||
pre
|
||||
$(pre +(pre))
|
||||
--
|
||||
```
|
||||
## Progress
|
||||
|
||||
In most functional languages, a function is a primitive. In Hoon
|
||||
it's a macro, and a pretty complex macro at that. We spent four
|
||||
chapters building the concept up out of much smaller pieces.
|
||||
|
||||
Fortunately, once you have functions you can do anything. We
|
||||
still have a fair bit to learn, but we've now seen all the
|
||||
fundamental building blocks of programming in Hoon. In the next
|
||||
chapter, we'll get back into molds and spans.
|
@ -1,322 +0,0 @@
|
||||
---
|
||||
title: Hoon 101.3: our first program
|
||||
sort: 3
|
||||
hide: true
|
||||
next: false
|
||||
---
|
||||
# Hoon 101.3: our first program
|
||||
|
||||
It's time for us to do some actual programming. In this section,
|
||||
we'll work through that classic Urbit pons asinorum, decrement.
|
||||
|
||||
If you learned Nock before Hoon, you've already done decrement.
|
||||
If not, all you need to know is that the only arithmetic
|
||||
intrinsic in Nock is increment -- in Hoon, the unary `.+` rune.
|
||||
So an actual decrement function is required.
|
||||
|
||||
In chapter 3, we write a decrement builder: more or less the
|
||||
simplest nontrivial Urbit program. We should be able to run this
|
||||
example:
|
||||
```
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
41
|
||||
```
|
||||
|
||||
## What's in that subject?
|
||||
|
||||
As we've seen, Hoon works by running a twig against a subject.
|
||||
We've been cheerfully running twigs through three chapters while
|
||||
avoiding the question: what's in the subject? To avoid the issue
|
||||
we've built a lot of constants, etc.
|
||||
|
||||
Of course your twig's subject comes from whoever runs it. There
|
||||
is no one true subject. Our twigs on the command line are not
|
||||
run against the same subject as our generator code, even though
|
||||
they are both run by the same `:dojo` appliance.
|
||||
|
||||
But the short answer is that both command-line and builder get
|
||||
*basically* the same subject: some ginormous noun containing all
|
||||
kinds of bells and whistles and slicers and dicers, including a
|
||||
kernel library which can needless to say decrement in its sleep.
|
||||
|
||||
As yet you have only faced human-sized nouns. We need not yet
|
||||
acquaint you with this mighty Yggdrasil, Mother of Trees. First
|
||||
we need to figure out what she could even be made of.
|
||||
|
||||
## Clearing the subject
|
||||
|
||||
We'll start by clearing the subject:
|
||||
```
|
||||
:- %say |= * :- %noun
|
||||
=> ~
|
||||
[%hello %world]
|
||||
```
|
||||
The `=>` rune ("tisgar"), for `=>(p q)` executes `p` against
|
||||
the subject, then uses that product as the subject of `q`.
|
||||
|
||||
(We've already used an irregular form of `=>`, or to be more
|
||||
precise its mirror `=<` ("tisgal"). In chapter 1, when we wrote
|
||||
`+3:test`, we meant `=>(test +3)` or `=<(+3 test)`.)
|
||||
|
||||
What is this `~`? It's Hoon `nil`, a zero atom with this span:
|
||||
```
|
||||
~tasfyn-partyv:dojo/sandbox> ?? ~
|
||||
[%cube 0 %atom %n]
|
||||
~
|
||||
```
|
||||
We use it for list terminators and the like. Obviously, since
|
||||
our old test code is just a constant, a null subject works fine:
|
||||
```
|
||||
~tasfyn-partyv:dojo/sandbox> +test
|
||||
[%hello %world]
|
||||
```
|
||||
|
||||
## Getting an argument
|
||||
|
||||
Obviously, if we want to write a decrement builder, we'll have to
|
||||
get an argument from the command line. This involves changing
|
||||
the `test.hoon` boilerplate a little:
|
||||
```
|
||||
:- %say |= [* [[arg=@ud ~] ~]] :- %noun
|
||||
=> arg=arg
|
||||
[%hello arg]
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
[%hello 42]
|
||||
```
|
||||
`=> arg=arg` looks a little odd. We wouldn't ordinarily do
|
||||
this. We're just replacing a very interesting subject that
|
||||
contains `arg` with a very boring one that contains only `arg`,
|
||||
for the same reason we cleared the subject with `~`.
|
||||
|
||||
In case there's any doubt about the subject (`.` is limb syntax
|
||||
for `+1`, ie, the whole noun):
|
||||
```
|
||||
:- %say |= [* [[arg=@ud ~] ~]] :- %noun
|
||||
=> arg=arg
|
||||
.
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
arg=42
|
||||
```
|
||||
|
||||
We can even write a trivial increment function using `.+`:
|
||||
```
|
||||
:- %say |= [* [[arg=@ud ~] ~]] :- %noun
|
||||
=> arg=arg
|
||||
+(arg)
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
43
|
||||
```
|
||||
Below we'll skip both boilerplate lines in our examples.
|
||||
|
||||
## A core is a code-data cell
|
||||
|
||||
But how do we actually, like, code? The algorithm for decrement
|
||||
is clear. We need to count up to 41. (How do we run useful
|
||||
programs on a computer with O(n) decrement? That's an
|
||||
implementation detail.)
|
||||
|
||||
We'll need another kind of noun: the *core*. Briefly, the core
|
||||
is always a cell `[battery payload]`. The payload is data, the
|
||||
battery is code -- one or more Nock formulas, to be exact.
|
||||
|
||||
Consider a simple core with a one-formula battery. Remember, we
|
||||
create Nock formulas by compiling a twig against a subject. The
|
||||
subject is dynamic data, but its span is static. What span do we
|
||||
give the compiler, and what noun do we give the formula?
|
||||
|
||||
A core formula always has the core as its subject. The formula
|
||||
is essentially a computed attribute on the payload. But if the
|
||||
subject was just the payload, the formula couldn't recurse.
|
||||
|
||||
Of course, there is no need to restrict ourselves to one computed
|
||||
attribute. We can just stick a bunch of formulas together and
|
||||
call them a battery. The source twigs in this core are called
|
||||
"arms," which have labels just like the faces we saw earlier.
|
||||
|
||||
Hoon overloads computed attributes (arms) and literal attributes
|
||||
(legs) in the same namespace. A label in a wing may refer to
|
||||
either. To extend the name-resolution tree search described in
|
||||
chapter 1, when searching a core, we look for a matching arm.
|
||||
If we find it we're done. If we don't, or if a `^` mark makes us
|
||||
skip, we search into the payload.
|
||||
|
||||
If a name resolves to a core arm, but it's not the last limb in the
|
||||
wing, the arm produces the core itself. Similarly, when the
|
||||
wing is not an access but a mutation, the arm refers to the core.
|
||||
|
||||
This demands an example: if `foo` produces some core `c`, and
|
||||
`bar` is an arm in that `c` (which may be `foo` itself, or some
|
||||
leg within `foo`), `bar.foo` runs the arm formula with `c` as the
|
||||
subject. You might think that `moo.bar.foo` would compute
|
||||
`bar.foo`, then search for `moo` within that result. Instead, it
|
||||
searches for `moo` within `c`. (You can get the other result
|
||||
with `moo:bar.foo`.)
|
||||
|
||||
Does this sound too tricky? It should - it's about the most
|
||||
complicated feature of Hoon. It's all downhill once you
|
||||
understand cores.
|
||||
|
||||
Let's again extend our `++span` mold:
|
||||
```
|
||||
++ span
|
||||
$% [%atom @tas]
|
||||
[%cell span span]
|
||||
[%core span (map ,@tas twig)]
|
||||
[%cube * span]
|
||||
[%face @tas span]
|
||||
==
|
||||
```
|
||||
This definition of `%core` is somewhat simplified from the
|
||||
reality, but basically conveys it. (Moreover, this version of
|
||||
`span` describes every kind of noun we build.) In our `%core` we
|
||||
see a payload span and a name-to-twig arm table, as expected.
|
||||
|
||||
Is a core an object? Not quite, because an arm is not a method.
|
||||
Methods in an OO language have arguments. Arms are functions
|
||||
only of the payload. (A method in Hoon is an arm that produces a
|
||||
gate, which is another core -- but we're getting too far ahead.)
|
||||
However, the battery does look a lot like a classic "vtable."
|
||||
|
||||
## Increment with a core
|
||||
|
||||
Let's increment with a core:
|
||||
```
|
||||
=< inc
|
||||
|%
|
||||
++ inc
|
||||
+(arg)
|
||||
--
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
43
|
||||
```
|
||||
What's going on? We used the `|%` rune ("barcen") to produce a
|
||||
core. (There are a lot of runes which create cores; they all
|
||||
start with `|`, and are basically macros that turn into `|%`.)
|
||||
|
||||
The payload of a core produced with `|%` is the subject with
|
||||
which `|%` is compiled. We might say that `|%` wraps a core
|
||||
around its subject. In this case, the subject of the `|%`,
|
||||
and thus payload, is our `arg=@ud` argument.
|
||||
|
||||
Then we used this core as the subject of the simple wing `inc`.
|
||||
(Remember that `=<(a b)` is just `=>(b a)`.)
|
||||
|
||||
We can actually print out a core. Take out the `=< inc`:
|
||||
```
|
||||
|%
|
||||
++ inc
|
||||
+(arg)
|
||||
--
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
!!!
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> ? +test 42
|
||||
!!!
|
||||
```
|
||||
Cores can be large and complex, and we obviously can't render all
|
||||
the data in them, either when printing a type or a value. At
|
||||
some point, you'll probably make the mistake of printing a big
|
||||
core, maybe even the whole kernel, as an untyped noun. Just
|
||||
press ^C.
|
||||
|
||||
## Adding a counter
|
||||
|
||||
To decrement, we need to count up to the argument. So we need a
|
||||
counter in our subject, because where else would it go? Let's
|
||||
change the subject to add a counter, `pre`:
|
||||
```
|
||||
=> [pre=0 .]
|
||||
=< inc
|
||||
|%
|
||||
++ inc
|
||||
+(arg)
|
||||
--
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
43
|
||||
```
|
||||
Once again, `.` is the whole subject, so we're wrapping it in a
|
||||
cell whose head is `pre=0`. Through the magic of labels, this
|
||||
doesn't change the way we use `arg`, even though it's one level
|
||||
deeper in the subject tree. Let's look at the subject again:
|
||||
```
|
||||
=> [pre=0 .]
|
||||
.
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
[pre=0 arg=42]
|
||||
~tasfyn-partyv:dojo/sandbox> ? +test 42
|
||||
[pre=@ud arg=@ud]
|
||||
[pre=0 arg=42]
|
||||
```
|
||||
There's actually a simpler way to write this. We've seen it
|
||||
already. It's not exactly a variable declaration:
|
||||
```
|
||||
=+ pre=0
|
||||
.
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
[pre=0 arg=42]
|
||||
```
|
||||
|
||||
## We actually decrement
|
||||
|
||||
Now we can write our actual decrement program:
|
||||
```
|
||||
=+ pre=0
|
||||
=< dec
|
||||
|%
|
||||
++ dec
|
||||
?: =(arg +(pre))
|
||||
pre
|
||||
dec(pre +(pre))
|
||||
--
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
41
|
||||
```
|
||||
`=(a b)` is an irregular form of `.=(a b)`, ie, "dottis" or the
|
||||
noun `[%dtts a b]`. Likewise, `+(a)` is `.+(a)`, ie, "dotlus"
|
||||
or `[%dtls a]`.
|
||||
|
||||
`?:` is a regular rune which does exactly what you think it does.
|
||||
Bear in mind, though, that in Hoon 0 (`&`, "pam") is true and 1
|
||||
(`|`, "bar") is false.
|
||||
|
||||
The real action is in `dec(pre +(pre))`. This is obviously an
|
||||
irregular form -- it's the same mutation form we saw before.
|
||||
Writing it out in full regular form:
|
||||
```
|
||||
=+ pre=0
|
||||
=< dec
|
||||
|%
|
||||
++ dec
|
||||
?: =(arg +(pre))
|
||||
pre
|
||||
%= dec
|
||||
pre +(pre)
|
||||
==
|
||||
--
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
41
|
||||
```
|
||||
`%=`, "centis", is the rune which almost every use of a wing
|
||||
resolves to. It might be called "evaluate with changes."
|
||||
|
||||
When we evaluate with changes, we take a wing (`dec`) here and
|
||||
evaluate it as described above. Searching in the subject, which
|
||||
is of course our core, we find an arm called `dec` and run it.
|
||||
|
||||
The changes (replacing `pre` with `+(pre)`) are always applied
|
||||
relative to the core we landed on (or the leg we landed on).
|
||||
The change wing is relative to this target; the subject of the
|
||||
replacement (`+(pre)`) is the original subject.
|
||||
|
||||
So, in English, we compute the `dec` arm again, against a new
|
||||
core with a new payload that contains an incremented `pre`.
|
||||
And thus, we decrement. Doesn't seem so hard, does it?
|
@ -1,267 +0,0 @@
|
||||
---
|
||||
title: Hoon 101.4: functions
|
||||
sort: 4
|
||||
hide: true
|
||||
next: false
|
||||
---
|
||||
# Hoon 4: toward actual functions
|
||||
|
||||
Okay, we've programmed. We've achieved decrement. We've written
|
||||
what is in some sense a loop. What next?
|
||||
|
||||
Well... we're still feeling vaguely disappointed. Because we're
|
||||
supposed to be doing *functional programming*. And we haven't
|
||||
yet written any *functions*.
|
||||
|
||||
After all, in Hoon we don't really write a command-line utility
|
||||
to decrement `42`. We write `(dec 42)`. You probably realize
|
||||
that on the inside, this is not the same thing as a function in a
|
||||
normal functional language. The Tasmanian tiger is not a tiger.
|
||||
On the other hand, it certainly *looks* like a function call.
|
||||
|
||||
So how do we write the function?
|
||||
|
||||
In this chapter, we'll modify `+test` to extend the subject so
|
||||
that we can write our result as `(dec arg)`. Or rather, `(duck
|
||||
arg)`, because we want to get out of training wheels and stop
|
||||
clearing the subject soon.
|
||||
|
||||
## Form of the solution
|
||||
|
||||
```
|
||||
=< :- %say |= [* [[arg=@ud ~] ~]] :- %noun
|
||||
(duck arg)
|
||||
!! :: some interesting core
|
||||
```
|
||||
`!!`, or "zapzap" or `[%zpzp ~]`, can go anywhere a twig can and
|
||||
always crashes. Because its span is the empty set (`%void`), it
|
||||
doesn't cause type inference problems.
|
||||
|
||||
In place of the `!!`, we'll put a core, effectively a library,
|
||||
that provides our new, improved decrement function `duck`. We'll
|
||||
then call it with the irregular form, `(duck arg)`, which looks
|
||||
like a function call but is in fact some mysterious macro.
|
||||
|
||||
## Some interesting core
|
||||
|
||||
Translated into imperative programming, what we did in chapter 3
|
||||
was more like computing a function of a global variable. Now,
|
||||
we have to actually pass an argument to a function.
|
||||
|
||||
Here's our first try:
|
||||
```
|
||||
=< :- %say |= [* [[arg=@ud ~] ~]] :- %noun
|
||||
=+ gat=duck
|
||||
=<(run gat(sam arg))
|
||||
=> ~
|
||||
|%
|
||||
++ duck
|
||||
=+ sam=0
|
||||
=+ pre=0
|
||||
|%
|
||||
++ run
|
||||
?: =(sam +(pre))
|
||||
pre
|
||||
run(pre +(pre))
|
||||
--
|
||||
--
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
41
|
||||
```
|
||||
We step back and contemplate our handiwork. Is it good? Well...
|
||||
it works. Reading programs written without syntactic sugar is
|
||||
about as fun as eating raw chocolate nibs.
|
||||
|
||||
What did we do? In the `duck` arm (we often write `++duck`, for
|
||||
obvious reasons) we produce a core whose payload is `[pre=0 num=0
|
||||
~]`, and whose battery contains `++run`.
|
||||
|
||||
In the result twig, we first use `++duck` to extend our subject
|
||||
with a core named `gat`. We then use `run` on that gate. Why do
|
||||
we need this `gat`? Why can't we just write `=<(run duck(sam
|
||||
arg))`?
|
||||
|
||||
Because the arm is computed *after* the mutation. But here we
|
||||
need the mutated *result* of `++duck`. Instead, what this code
|
||||
is doing is trying to mutate `sam` within the core that contains
|
||||
`++duck`. Where it doesn't exist, so your code won't compile.
|
||||
|
||||
And note that with `=<`, we've placed our library structurally
|
||||
between the original subject and the program we're writing,
|
||||
but lexically at the bottom with zero left margin. We also
|
||||
clear the subject to keep things simple.
|
||||
|
||||
## A more regular structure
|
||||
|
||||
It actually gets worse. To make this code look simpler, we need
|
||||
to make it more complex. While "function calls" actually fit
|
||||
quite well into the Hoon architecture, they're also a nontrivial
|
||||
synthetic construction. We'll build the desugared form the hard
|
||||
way, then show you where we put the sugar in.
|
||||
|
||||
The desugared canonical decrement:
|
||||
```
|
||||
=< :- %say |= [* [[arg=@ud ~] ~]] :- %noun
|
||||
=+ gat=duck
|
||||
=<(run gat(sam arg))
|
||||
=> ~
|
||||
|%
|
||||
++ duck
|
||||
=+ sam=0
|
||||
|%
|
||||
++ run
|
||||
=+ pre=0
|
||||
=< loop
|
||||
|%
|
||||
++ loop
|
||||
?: =(sam +(pre))
|
||||
pre
|
||||
loop(pre +(pre))
|
||||
--
|
||||
--
|
||||
--
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
41
|
||||
```
|
||||
Yuck. Okay, let's fix this.
|
||||
|
||||
## Art of the loop
|
||||
|
||||
First, look at our little `++loop`. It works just like our old
|
||||
`++run` loop. We notice that there's actually something nice
|
||||
about it: we don't use the symbol `loop` anywhere outside these 7
|
||||
lines of code. It's not exported at all.
|
||||
|
||||
Actually, the symbol `loop` name is useless and redundant.
|
||||
Making up names is one of the hard problems in computer science,
|
||||
so why solve it? For just this reason, Hoon has an *empty name*,
|
||||
which as a constant is a zero-length symbol (`%$` instead of
|
||||
`%foo`), and as a limb is the `buc` symbol (`$`). With `$`,
|
||||
our loop becomes:
|
||||
```
|
||||
=< $
|
||||
|%
|
||||
++ $
|
||||
?: =(sam +(pre))
|
||||
pre
|
||||
$(sam +(run))
|
||||
--
|
||||
```
|
||||
This may not seem like a huge improvement. It's not. But it's
|
||||
exactly equivalent to the synthetic rune `|-`, "bardas":
|
||||
```
|
||||
|- ?: =(sam +(pre))
|
||||
pre
|
||||
$(pre +(pre))
|
||||
```
|
||||
This is obviously the canonical Hoon loop. It leaves us with
|
||||
```
|
||||
=< :- %say |= [* [[arg=@ud ~] ~]] :- %noun
|
||||
=+ gat=duck
|
||||
=<(run gat(sam arg))
|
||||
=> ~
|
||||
|%
|
||||
++ duck
|
||||
=+ sam=0
|
||||
|%
|
||||
++ run
|
||||
=+ pre=0
|
||||
|- ?: =(sam +(pre))
|
||||
pre
|
||||
$(pre +(pre))
|
||||
--
|
||||
--
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
41
|
||||
```
|
||||
|
||||
## Is this a lambda?
|
||||
|
||||
Could we use `$` for `++run`? It certainly sounds like the same
|
||||
kind of thing as `++loop` -- just a word we invented to mean "do
|
||||
it." Should the programmer have to invent these kinds of words?
|
||||
```
|
||||
=< :- %say |= [* [[arg=@ud ~] ~]] :- %noun
|
||||
=+ gat=duck
|
||||
=<($ gat(sam arg))
|
||||
=> ~
|
||||
|%
|
||||
++ duck
|
||||
=| sam=@ud
|
||||
|%
|
||||
=+ pre=0
|
||||
++ $
|
||||
|- ?: =(sam +(pre))
|
||||
pre
|
||||
$(pre +(pre))
|
||||
--
|
||||
--
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
41
|
||||
```
|
||||
(Besides `run` to `$`, we changed `=+ sam=0` to `=| sam=@ud`.
|
||||
Let's just remember that there's some magic here. We'll come
|
||||
back and explain it later.)
|
||||
|
||||
This is still kind of ugly -- but it's exactly equivalent to
|
||||
```
|
||||
=< :- %say |= [* [[arg=@ud ~] ~]] :- %noun
|
||||
=+ gat=duck
|
||||
=<($ gat(sam arg))
|
||||
=> ~
|
||||
|%
|
||||
++ duck
|
||||
|= sam=@ud
|
||||
=+ pre=0
|
||||
|- ?: =(sam +(pre))
|
||||
pre
|
||||
$(pre +(pre))
|
||||
--
|
||||
|
||||
~tasfyn-partyv:dojo/sandbox> +test 42
|
||||
41
|
||||
```
|
||||
Doesn't that look like a function? Indeed, we're done with
|
||||
`++duck` -- that's what a Hoon decrement should look like.
|
||||
If you squint a little, `|=` ("bartis") might even be a strange,
|
||||
deformed lambda rune.
|
||||
|
||||
Since it's doing something simple, we might well even compress
|
||||
the whole body of the function into one wide-form line:
|
||||
```
|
||||
=+(pre=0 |-(?:(=(sam +(pre)) pre $(pre +(pre)))))
|
||||
```
|
||||
(According, of course, to taste -- this is a bit tight for some.)
|
||||
|
||||
## Gates and how to call them
|
||||
|
||||
Our call site remains a disaster, though. We'll need moar sugar.
|
||||
|
||||
But first, let's look at this lambda-thing we've made. What is
|
||||
the noun produced by `++duck`? Our term for it is a "gate," but
|
||||
nobody will hate you for saying "function." And while we "slam"
|
||||
our gates, you can feel free to just "call" them.
|
||||
|
||||
A gate is a core, of course, but a special kind of core. All
|
||||
cores are shaped like `[battery payload]`. A gate is shaped like
|
||||
`[formula [sample context]]`. A gate has one arm, `$`, so its
|
||||
battery is just a formula. To slam a gate, you replace its
|
||||
sample (`+6` or `+<`, "luslit" or "lust") with your own noun,
|
||||
and apply the formula to the mutated gate.
|
||||
|
||||
As we explained earlier, `duck(sam arg)` is not the right way to
|
||||
mutate the gate we make with `duck`, because it's actually
|
||||
trying to mutate the core we used to make `duck`. But there has
|
||||
to be some sugar to do this, and there is: `%*`, "centar". We
|
||||
can replace our call site with `%*($ duck sam arg)`.
|
||||
|
||||
This is also not quite orthodox, because the whole point of a
|
||||
gate is the canonical shape that defines a calling convention.
|
||||
We can and should say: `%*($ duck +< arg)`.
|
||||
|
||||
Unsurprisingly, this in turn is `%-(duck arg)` in regular form,
|
||||
or `(duck arg)`
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
logo: black
|
||||
title: User doc
|
||||
sort: 1
|
||||
title: User doc
|
||||
---
|
||||
|
||||
<div class="short">
|
||||
@ -10,9 +10,9 @@ sort: 1
|
||||
|
||||
Read the [introduction](user/intro) for a summary of Urbit.
|
||||
The [installation guide](user/install) gets you ready to run.
|
||||
The [launch procedure](user/launch) holds your hand as you create
|
||||
your server image. Once your urbit is live, the [quickstart
|
||||
page](user/start) is all you need if in a hurry.
|
||||
Launch with [basic operation](user/basic) and get a feel for the
|
||||
system. Once your urbit is live, the [walking tour](user/tour)
|
||||
shows how to do some common tasks.
|
||||
|
||||
For power users, the [appliance handbook](user/appliance) explains
|
||||
your apps and how to control them. The [filesystem handbook](user/clay)
|
||||
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Appliance handbook
|
||||
sort: 5
|
||||
next: true
|
||||
sort: 5
|
||||
title: Appliance handbook
|
||||
---
|
||||
|
||||
# Appliance handbook
|
||||
|
143
pub/docs/user/basic.mdy
Normal file
143
pub/docs/user/basic.mdy
Normal file
@ -0,0 +1,143 @@
|
||||
---
|
||||
next: true
|
||||
sort: 3
|
||||
title: Basic Operation
|
||||
---
|
||||
|
||||
# Basic Operation
|
||||
|
||||
Once urbit is installed, if you have an invitation, it's a planet
|
||||
like `~fintud-macrep` and a ticket like
|
||||
`~fortyv-tombyt-tabsen-sonres`. Run
|
||||
|
||||
bin/urbit -w fintud-macrep -t fortyv-tombyt-tabsen-sonres
|
||||
|
||||
(You can leave the `~` on, but it annoys some Unix shells.)
|
||||
|
||||
If you don't have an invitation, pick a nickname for your comet,
|
||||
like `mycomet`. Urbit will randomly generate a 128-bit plot:
|
||||
|
||||
bin/urbit -c mycomet
|
||||
|
||||
Either way, creating your urbit will take some time. Some of
|
||||
this time involves generating keys; some of it involves
|
||||
downloading code over Urbit itself.
|
||||
|
||||
If you turn off your pier at any time (either "nicely" with `^D`
|
||||
from talk or the dojo or by power-failure, oom-killer, or other
|
||||
calamity), then you can start it up again with the path to your
|
||||
pier directory (your planet name if you have an invitation,
|
||||
otherwise the name you chose after `-c`):
|
||||
|
||||
bin/urbit fintud-macrep
|
||||
|
||||
or
|
||||
|
||||
bin/urbit mycomet
|
||||
|
||||
## Basic operation
|
||||
|
||||
Out of the box, your urbit is running two default appliances,
|
||||
`:dojo` (a shell or REPL) and `:talk`. Switch between them with
|
||||
`^X`. Note that all apps share an output log, but `^X` switches
|
||||
the prompt.
|
||||
|
||||
`^D` from either default appliance exits the urbit process.
|
||||
|
||||
If your plot is `~fintud-macrep`, the dojo prompt is
|
||||
|
||||
~fintud-macrep:dojo>
|
||||
|
||||
Type any Hoon expression at the command line and see the result:
|
||||
|
||||
~fintud-macrep:dojo> (add 2 2)
|
||||
|
||||
You'll see:
|
||||
|
||||
> (add 2 2)
|
||||
4
|
||||
~fintud-macrep:dojo>
|
||||
|
||||
While there are some tools for interacting with urbit's
|
||||
filesystem direclty, often it's useful to edit urbit files from
|
||||
Unix. Use `|mount` to set up a Dropbox-style sync directory in
|
||||
your pier directory:
|
||||
|
||||
~fintud-macrep:dojo> |mount %
|
||||
>=
|
||||
~fintud-macrep:dojo> |unmount %
|
||||
>=
|
||||
|
||||
Look inside your pier directory to find your files, and edit them
|
||||
with your favorite Unix text editor.
|
||||
|
||||
Sometimes you want to get files from another urbit. There's two
|
||||
main commands to do this.
|
||||
|
||||
~fintud-macrep:dojo> |merge %examples ~wactex-ribmex %examples
|
||||
>=
|
||||
; ~wactex-ribmex is your neighbor
|
||||
; ~wactex-ribmex is your neighbor
|
||||
[time passes...]
|
||||
merged with strategy %init
|
||||
|
||||
This pulls a bunch of examples from `~wactex-ribmex`'s `%examples`
|
||||
desk and puts them in our `%examples` desk. A desk is a
|
||||
branch (in the git branch sense) of our filesystem.
|
||||
|
||||
You can, of course, merge the examples into your `%home`
|
||||
(default) desk if you wish. Merging into a new desk creates it,
|
||||
while merging into an existing desk does an intelligent git-style
|
||||
merge, with conflict resolution and stuff.
|
||||
|
||||
~fintud-macrep:dojo> |sync %examples ~wactex-ribmex %examples
|
||||
>=
|
||||
activated sync from %examples on ~wactex-ribmex to %examples
|
||||
sync succeeded from %examples on ~wactex-ribmex to %examples
|
||||
~fintud-macrep:dojo> |unsync %examples ~wactex-ribmex %examples
|
||||
ended autosync from %examples on ~wactex-ribmex to %examples
|
||||
|
||||
`|sync` does an initial `|merge`, then listens for changes on the
|
||||
foreign desk and runs `|merge` automatically whenever it changes.
|
||||
By default your `%home` desk is synced to your parent's `%kids`
|
||||
desk, so the entire network is upgraded at once. You may, of
|
||||
course, unsync it, but this voids your warranty.
|
||||
|
||||
You can change which desk is your current working directory with:
|
||||
|
||||
~fintud-macrep:dojo> =dir /=examples
|
||||
|
||||
> `dir` is a special dojo variable, but you can also create your
|
||||
> own variables with the same syntax. `=my-var (add 2 3)` allows
|
||||
> you to use `my-var` for `5` anywhere later on.
|
||||
|
||||
When you change your desk all commands will use the files from
|
||||
that desk. Unfortunately, changing your working directory to
|
||||
anywhere but the top directory is currently
|
||||
[broken](http://github.com/urbit/urbit/issues/565). If this is
|
||||
fixed when you're reading this, please submit a pull request for
|
||||
this document explaining how to do it!
|
||||
|
||||
The last command we'll discuss in this quickstart is `+moon`,
|
||||
which only works on planets.
|
||||
|
||||
~fintud-macrep:dojo> +moon
|
||||
"moon: ~ramnec-rossug-fintud-macrep; ticket: ~holtyl-mognyl-dostyp-moslud"
|
||||
|
||||
This generates a random moon and ticket. A moon is a subidentity
|
||||
of your planet, so it's a separate urbit that's associated with
|
||||
your planet. If your planet is off, then your moon won't
|
||||
function very well over the network (it'll work just fine
|
||||
locally, of coures).
|
||||
|
||||
You can start up your moon with `bin/urbit -w moon-name -t
|
||||
ticket`. We recommend doing this for development because there
|
||||
are still some instabilities that have the potential to explode
|
||||
your planet if you develop on it. If this happens, then your
|
||||
planet will be unusable until the next continuity breach. If you
|
||||
tell us how you exploded your planet, we may give you a
|
||||
replacement, but it's still a hassle for you.
|
||||
|
||||
Don't worry too much about exploding your moons -- you have four
|
||||
billion of them, and they get replenished after every continuity
|
||||
breach. Still do file a bug, though.
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Filesystem handbook
|
||||
sort: 6
|
||||
next: true
|
||||
sort: 6
|
||||
title: Filesystem handbook
|
||||
---
|
||||
|
||||
# Filesystem handbook
|
||||
|
@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Dojo manual
|
||||
sort: 8
|
||||
title: Dojo manual
|
||||
---
|
||||
|
||||
# `:dojo` manual
|
||||
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Install
|
||||
sort: 2
|
||||
next: true
|
||||
sort: 2
|
||||
title: Install
|
||||
---
|
||||
|
||||
# Installation guide
|
||||
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Introduction
|
||||
sort: 1
|
||||
next: true
|
||||
sort: 1
|
||||
title: Introduction
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
@ -1,7 +1,8 @@
|
||||
---
|
||||
title: Launch
|
||||
sort: 3
|
||||
hide: true
|
||||
next: true
|
||||
sort: 10
|
||||
title: Launch
|
||||
---
|
||||
|
||||
# Launch procedure
|
||||
|
@ -1,7 +1,7 @@
|
||||
---
|
||||
title: Talk manual
|
||||
sort: 7
|
||||
next: true
|
||||
sort: 7
|
||||
title: Talk manual
|
||||
---
|
||||
|
||||
# `:talk` manual
|
||||
|
@ -1,20 +1,10 @@
|
||||
---
|
||||
title: Quickstart
|
||||
sort: 4
|
||||
next: true
|
||||
sort: 4
|
||||
title: Walking Tour
|
||||
---
|
||||
|
||||
# Quickstart
|
||||
|
||||
To start your already-launched urbit, just run `urbit` with one
|
||||
argument, which is the pier directory (`$PIER`). This is your
|
||||
planet name if you have a planet, or the name you used with `-c`
|
||||
if you have a comet:
|
||||
|
||||
bin/urbit fintud-macrep
|
||||
or
|
||||
|
||||
bin/urbit mycomet
|
||||
# Walking Tour
|
||||
|
||||
Piers are portable. You can move a pier anywhere. But never,
|
||||
*ever* run the same urbit in two places at once. (If you try to
|
||||
@ -24,31 +14,6 @@ pier, Urbit will kill the old process.)
|
||||
(Also, don't let the Unix filesystem it's on run out of disk.
|
||||
This is a known way to corrupt your urbit! Sorry.)
|
||||
|
||||
## Basic operation
|
||||
|
||||
Out of the box, your urbit is running two default appliances,
|
||||
`:dojo` (a shell or REPL) and `:talk`. Switch between them with
|
||||
`^X`. Note that all apps share an output log, but `^X` switches
|
||||
the prompt.
|
||||
|
||||
`^D` from any default appliance exits the urbit process.
|
||||
|
||||
## Compute: your `:dojo` appliance
|
||||
|
||||
If your plot is `~fintud-macrep`, the dojo prompt is
|
||||
|
||||
~fintud-macrep:dojo>
|
||||
|
||||
Type any Hoon expression at the command line and see the result:
|
||||
|
||||
~fintud-macrep:dojo> (add 2 2)
|
||||
|
||||
You'll see:
|
||||
|
||||
> (add 2 2)
|
||||
4
|
||||
~fintud-macrep:dojo>
|
||||
|
||||
### Dojo expressions, generators and operators
|
||||
|
||||
`:dojo` is of course a command-line REPL or shell. But it
|
||||
@ -96,7 +61,8 @@ You're on the air! You should see some backlog to give you
|
||||
context. Please remember our code of conduct: don't be rude.
|
||||
Also, `urbit-meta` is politically correct and safe for work.
|
||||
|
||||
For more instructions on how to use `:talk`, see the [`:talk` manual](http://urbit.org/docs/user/talk)
|
||||
For more instructions on how to use `:talk`, see the [`:talk`
|
||||
manual](http://urbit.org/docs/user/talk)
|
||||
|
||||
## Using the filesystem
|
||||
|
@ -1,4 +1,4 @@
|
||||
::
|
||||
::
|
||||
:::: /hoon/sole/sur
|
||||
!:
|
||||
|%
|
||||
@ -36,6 +36,7 @@
|
||||
[%tan p=(list tank)] :: classic tank
|
||||
:: [%taq p=tanq] :: modern tank
|
||||
[%txt p=tape] :: text line
|
||||
[%url p=@t] :: activate url
|
||||
== ::
|
||||
++ sole-command :: command state
|
||||
$: pos=@ud :: cursor position
|
||||
|
Loading…
Reference in New Issue
Block a user