diff --git a/Foi-Guide.md b/Foi-Guide.md index 714968e..6f9b77c 100644 --- a/Foi-Guide.md +++ b/Foi-Guide.md @@ -858,6 +858,8 @@ def greeting: ?(myName){ greeting; // "Hello!" ``` +The `?:` else-clause can also be abbreviated as `:` if preferred. More on that in a bit. + **Note:** Comparing this example to the previous one, `?:` is equivalent to the `!["Kyle"]` pattern. Readability preferences may dictate either style, depending on the circumstances. A dependent style pattern can include a `,` comma separated list of multiple values, any of which may match the topic: @@ -907,7 +909,7 @@ greeting; // "Hello!" **Note:** The pattern-match conditional `![myName ?= "Kyle"]` is equivalent to `?[myName != "Kyle"]`. Readability preferences may dictate either style, depending on the circumstances. -Just as with dependent pattern matching, it's preferable for the overall independent pattern matching expression to be determinate, in that all conditional branches are covered. Again, to define a default (final) clause, `?:` may be used: +Just as with dependent pattern matching, it's preferable for the overall independent pattern matching expression to be determinate, in that all conditional branches are covered. Again, to define a default (final) clause, `?:` (or abbreviated `:`) may be used: ```java def myName: "Kyle"; @@ -930,13 +932,13 @@ Pattern-matching conditional clauses may optionally skip the leading `?` type-sp ?{ [isLoggedIn()]: showDashboard(); [isRegistered()]: showLogin(); - default: showRegistration() + : showRegistration() }; ``` -Here, the two `[ .. ]: ..` clauses skip the leading type-signifier (a `?` is assumed). However, the `!` type signifier is never assumed, and therefore must be explicitly stated for clauses. +Here, the two `[ .. ]: ..` clauses skip the leading type-signifier (a `?` is assumed). However, the `!` type signifier is never assumed, and therefore must be explicitly stated for clauses. As mentioned earlier, the `:` by itself on the third line illustrates an abbreviated `?:` else-clause. -In cases where both affirmative and negative clauses are present, it may be desirable (for visual consistency) to specify both the `?` and `!` signifiers on the respective clauses, rather than only the `!` being present and the `?` being omitted. For example: +In cases where both affirmative and negative clauses are present, it may be desirable (for visual consistency) to specify both the `?` and `!` signifiers on the respective clauses, rather than only the `!` being present and the `?` being assumed. For example: ```java // style 1 @@ -965,16 +967,18 @@ def myName: "Kyle"; // full pattern matching expression: ?{ - ?[!empty myName]: printGreeting(myName) + [!empty myName]: printGreeting(myName) } // standalone guard expression: ?[!empty myName]: printGreeting(myName); -// or: +// equivalent, if you prefer: ![?empty myName]: printGreeting(myName); ``` +The leading `?` is required on standalone guard expressions, unlike the optional abbreviated form in pattern matching. + ## Records And Tuples Records are immutable collections of values, delimited by `< >`. diff --git a/Grammar.md b/Grammar.md index 75dd58d..17f3c2b 100644 --- a/Grammar.md +++ b/Grammar.md @@ -228,7 +228,7 @@ IndepPatternStmt := IndepCondClause MatchConsequent (WhSp* ";")*; IndepCondClause := ("?" | "!" | Epsilon) BracketExpr; MatchConsequentNoSemi := ":" WhSp* ExprAsOpt | BlockExpr; MatchConsequent := ":" WhSp* ((ExprAsOpt WhSp* ";") | BlockExpr); -ElseStmt := "?" MatchConsequentNoSemi (WhSp* ";")*; +ElseStmt := "?"? MatchConsequentNoSemi (WhSp* ";")*; DepMatchExpr := "?(" WhSp* ExprNoBlockAsOpt WhSp* "){" WhSp* DepPatternStmts WhSp* "}"; DepPatternStmts := DepPatternStmtNoSemi | ((DepPatternStmt WhSp*)+ (ElseStmt | DepPatternStmtNoSemi)?) | ElseStmt; DepPatternStmtNoSemi := DepCondClause MatchConsequentNoSemi; diff --git a/README.md b/README.md index 345bd10..a983e51 100644 --- a/README.md +++ b/README.md @@ -20,9 +20,42 @@ defn greetings(who) { The language is designed for general application programming purposes, but with a clear emphasis on FP (and de-emphasis on OOP). It's not trying to compete in performance or capability with systems languages like C or Rust. Eventually, **Foi** will compile to WASM so it should be usable for applications in a variety of environments, from the web to the server to mobile devices. -An important design goal is that a somewhat experienced developer -- especially one with both FP and imperative experience/curiosity -- should be able to sufficiently/fully learn **Foi** in a few days. It also shouldn't take reading thousands of pages of books or watching months of workshop videos to fully grasp the surface area of **Foi**. +An important design goal is that a somewhat experienced developer -- especially one with both FP and imperative experience/curiosity -- should be able to sufficiently or fully learn **Foi** in several days. -Hopefully, without too much heavy orientation, code like this will settle into familiarity for you: +In the following code snippet, you'll might recognize familiar mechanisms like function calls and pattern recognition. There's also some standard FP idioms like partial application and composition (and a monad!). You might also spot a fun trick (operators-as-functions)! + +```java +def adder: arithmetic("add"); +def subtractor: arithmetic("subtract"); +def tripler: (*)|3|; +def add3: adder|3|; +def sub5: subtractor|,5|; +def compute: tripler +> add3 +> sub5; + +adder(3, 4); // 7 +add3(4); // 7 +subtractor(12, 5); // 7 +sub5(12); // 7 + +3 #> tripler #> adder(3, #) #> sub5; // 7 + +compute(3); // 7 +(<+)(sub5, add3, tripler)(3); // 7 + +// *********************** + +defn arithmetic(op) ^( + ?(op){ + ["add"]: (+); + ["subtract"]: (-); + ["multiply"]: (*); + ["divide"]: (/); + : Left@ "Invalid" + } +) +``` + +It shouldn't take reading thousands of pages of books or watching months of workshop videos to fully grasp the surface area of **Foi**. Hopefully, without too much learning and practice, even more advanced code like this will brighten into clarity: ```java defn getFavoriteMovies(userID) ^(IO ~<< { @@ -43,6 +76,8 @@ defn getFavoriteMovies(userID) ^(IO ~<< { getFavoriteMovies(123).run(document) ``` +**Hint:** The above snippet defines a function using the "do-syntax" against the `IO` monad, where the `::` definitions are monadic chain operations. Don't worry if that's just a bowl of word-soup for now. You'll *get it* before too long! + ## TL;DR If you're already convinced and ready to jump in, you may want to check these out next: