[HN Gopher] Tao: A statically-typed functional language
___________________________________________________________________
 
Tao: A statically-typed functional language
 
Author : memorable
Score  : 214 points
Date   : 2022-07-04 14:11 UTC (1 days ago)
 
web link (github.com)
w3m dump (github.com)
 
| tm-guimaraes wrote:
| The promises are great, but will it deliver? It's seems the
| language has a really huge scope with lots of hard problems to
| solve.
| 
| The thing I loved about golang was that it's just "good enough"
| in lots of areas instead of being the best or perfect. That
| allowed more time ti works on other parts of an ecosystem.
| 
| But since Tao is an hobby project, i just hope the author goes
| nuts and enjoy working on all those things. It is indeed a cool
| lang.
 
  | zesterer wrote:
  | I am indeed "going nuts"!
  | 
  | As mentioned in the README, I don't see Tao as a production-
  | quality language (at least, for the foreseeable future). I'll
  | leave that to the experts. Instead, I'm more interested in
  | exploring the limits of new language design ideas (effect
  | systems in particular). There are already a few interesting
  | things Tao does that I've not seen elsewhere.
 
    | landonxjames wrote:
    | Came across this post [0] by Graydon Hoare (original author
    | of Rust and member of the Swift team) in an HN comment the
    | other day. Lots of interesting discussion about future paths
    | for language design work, including some discussion of
    | Effects Systems.
    | 
    | Curious how Tao is pushing the limits on that front?
    | 
    | [0] https://graydon2.dreamwidth.org/253769.html
 
      | zesterer wrote:
      | > Curious how Tao is pushing the limits on that front?
      | 
      | I don't want to put emphasis on "pushing the limits"
      | because I'm still very new to language design and mostly
      | self-taught. There are bigger and better languages pushing
      | the envelope further than Tao!
      | 
      | That said, I've been experimenting with:
      | 
      | - Expressing totality and type inhabitance in the type
      | system
      | 
      | - Effect systems (including user-defined effects, effect
      | handling, parametric effects, lowering to monadic IO, etc.)
      | 
      | - Typeclass inference via typeclass variables (Tao can
      | handle several cases that are ambiguous even in Rust, such
      | as the following: https://github.com/zesterer/tao/blob/mast
      | er/examples/debug.t...)
 
        | skavi wrote:
        | would you mind explaining the linked code?
 
        | zesterer wrote:
        | The code is a bit of a gimmick, not really the sort of
        | thing you'd have in a real program. It's just there to
        | demonstrate that the compiler doesn't need explicitly
        | telling which typeclasses associated types correspond to.
        | That said:                   fn show_negative A : A ->
        | Str where             A < Neg,             A.Output <
        | Neg,             A.Output.Output < Neg,
        | A.Output.Output.Output < Neg,
        | A.Output.Output.Output.Output < Show,         =
        | a => (----a)->show
        | 
        | This is a function, called `show_negative`, that is
        | generic over a type, `A`. The function takes an instance
        | of `A` and returns a `Str` (string).
        | 
        | In terms of implementation, the function is quite simple:
        | it just negates the input value a bunch of time and then
        | `show`s it as a string using the `Show` typeclass
        | (equivalent to Haskell's `show`: https://hackage.haskell.
        | org/package/base-4.16.1.0/docs/Prelu...).
        | 
        | Arithmetic operations such as negation are defined using
        | typeclasses. Here's the definition of `Neg`:
        | class Neg =             => Output             => neg :
        | Self -> Self.Output
        | 
        | This means that types that can be negated must provide
        | two things: an output type produced when they're negated,
        | and a function that actually performs the negation. For
        | example, `Nat` (natural number) looks like:
        | member Nat of Neg =             => Output = Int
        | => neg = fn x => (implementation omitted because it's a
        | built-in intrinsic)
        | 
        | i.e: when you negate a `Nat`, you get an `Int`.
        | 
        | The `where` clauses on the `show_negative` just
        | constrains the output type of negating the `A` in such a
        | way that _its_ output type is also constrained, in a
        | chain, with the final type in the chain being
        | `show`-able.
 
| LelouBil wrote:
| A couple of months agow I had never tried functional programming
| languages. Having learned Rust in the past year (and loving it )
| made me want to try out Haskell since I always wondered about
| functional languages and I likes Rust's strong type system.
| 
| I go a bit dissappointed with Haskell, but right now I'm reading
| Tao's README and this looks like everything I've ever wanted !
| I'm gonna try it out right now.
 
  | throwaway17_17 wrote:
  | Can you expand on what disappointed you about Haskell. I'm not
  | looking to convert you or anything, just curious.
 
| okasaki wrote:
| Sorry, what's that font in the github screenshots?
 
  | zesterer wrote:
  | Iosevka Fixed Slab Semibold
 
| kortex wrote:
| Nice work! Looks super interesting and rewarding to work on.
| 
| Is the namesake "tao" meaning "the way"? Or perchance a nod to
| Terry Tao?
 
  | zesterer wrote:
  | > Tao or Dao is the natural order of the universe whose
  | character one's intuition must discern to realize the potential
  | for individual wisdom
  | 
  | It echoes how I feel when I write programs in languages with
  | strong static type systems: that of the compiler almost
  | fatalistically leading me towards a solution that naturally
  | fits the problem space. A metaphor I like to use is that of an
  | artist knocking away pieces of marble to reveal the statue that
  | was always there beneath.
  | 
  | And, yes, it's great fun to work on! Everybody should give
  | writing a compiler and designing a language a try!
 
| pjmlp wrote:
| I guess not to mix with Tao, next gen OS for Amiga, based on
| bytecode as distribution format.
| 
| https://www.edn.com/amiga-reborn-via-tao-alliance/
 
| lloydatkinson wrote:
| Somewhat familiar with FP and enjoy some of its benefits in my
| projects but I haven't really used a full blown FP language like
| Haskell. What exactly is a type class? I haven't found an
| explanation that makes a lot of sense to me. I think at one time
| I believed them to be some kind of contract like an interface in
| a OO language.
| 
| Can someone explain?
 
  | zesterer wrote:
  | A typeclass (or in Rust, a trait) is something that describes a
  | set of behaviours that must be implemented by a type (in OOP
  | languages, abstract classes are broadly equivalent).
  | 
  | For example, the typeclass `Eq` describes how values of a type
  | might be compared for equality.                   class Eq =
  | => eq : Self -> Self -> Bool
  | 
  | The typeclass requires that types conforming to it provide a
  | function, `eq`, that takes two instances of itself and returns
  | a bool (indicating whether the instances are equal). And member
  | of this typeclass might look like:                   for A, B
  | member (A, B) of Eq where             A < Eq,             B <
  | Eq,         =             => eq = fn (a0, b0), (b0, b1) => a0
  | == a1 && b0 == b1
  | 
  | You can read this as "for any two types, A and B, a tuple of
  | both can also be compared for equality provided both A and B
  | can themselves be compared for equality"
  | 
  | Typeclasses become useful because they allow you to constrain
  | generic type parameters. For example, we can now write a
  | function that determines whether a list contains a matching
  | value:                   fn contains A : A -> [A] -> Bool where
  | A < Eq,         =             | _, [] => False             \ k,
  | [x .. xs] => x == k || xs->contains(k)
  | 
  | All of this is checked at compile-time by the compiler,
  | ensuring that the function can only be called with types that
  | can be compared for equality.
 
  | lmm wrote:
  | One of the things that's hard to follow is that people conflate
  | typeclasses and typeclass instances.
  | 
  | So, the typeclass itself is like an interface, but rather than
  | having classes that implement that interface directly, you have
  | typeclass instances which are like an adapter between a value
  | (struct) and the interface - or like a virtual function table.
  | You know how a class instance is essentially a struct + a
  | (pointer to a) virtual function table? Imagine making those two
  | pieces more distinct in code - the typeclass instance is the
  | stanadlone virtual function table.
  | 
  | So your object state is more exposed - you can't really have
  | private fields in this paradigm since your state is just a
  | struct value. But it's clearer what's what, and it's much
  | easier to adapt types to interfaces even when the authors
  | didn't know about each other, since the typeclass instance can
  | be defined separately from both the typeclass and the value
  | type (although there are possible inference problems with
  | this). So lots of secondary cross-cutting functionality
  | problems where OO languages tend to end up with an ad-hoc type
  | registry (e.g. serialization or database mapping - just look at
  | what projects like jackson-datatype-joda or joda-time-hibernate
  | have to do to get themselves registered) are easier to solve in
  | this model.
 
| galaxyLogic wrote:
| What about OOP classes and inheritance? Data hiding? Modules?
 
  | zesterer wrote:
  | Tao has typeclasses (like Haskell) that allow for compositional
  | parameteric polymorphism. It also has data types (records, sum
  | types, etc.) and functions, but deliberately does not bundle
  | the two together.
  | 
  | There is no module system yet (only a temporary C-like #include
  | system): that's on my list of things to work on!
 
| toastal wrote:
| I don't understand what the possible use case for using a \ for
| the final bar for sum types would be. It would just make it a
| diff to add a new item at the end. I was hoping it had Unicode
| support looking at the example screenshot, but no, it's just a
| ligature font confusing users.
 
  | zesterer wrote:
  | Tao isn't indentation-sensitive, so nested `match` expressions
  | are ambiguous without the trailing \ branch.
  | 
  | I don't know whether I'll keep this syntax though. I'm
  | increasingly wondering whether it's better to just bite the
  | bullet and go all in with indentation sensitivity.
  | 
  | That said, the existing \ syntax can be quite nice to read:
  | https://github.com/zesterer/tao/blob/master/lib/parse.tao#L5...
 
    | ratww wrote:
    | The \ syntax is my favorite part so far, I'm definitely gonna
    | copy it for my toy language, hope that's ok ;)
 
      | zesterer wrote:
      | Go for it! IIRC it was suggested by someone else in the
      | #langdev channel on the Rust Community Discord, so I can't
      | claim to own the idea.
 
    | catlifeonmars wrote:
    | Why not just require parents for nested cases? IMO this is
    | fairly unambiguous, even to people unfamiliar with a
    | particular language.
 
      | zesterer wrote:
      | In a previous revision of the language, I did!
      | (https://github.com/zesterer/tao/tree/old). I decided
      | against it because, in short, I find the trailing
      | delimiters to be quite ugly.
      | 
      | Because this is purely a personal project, I'm thankfully
      | not constrained by such mundane concerns as "ergonomics"
      | (unless such concerns relate to me while I'm working with
      | it). I think Pythonic syntax is probably the way to go
      | long-term though...
 
        | patrickkidger wrote:
        | Personally I'm a big fan of Julia's syntax here.
        | Indentation-insensitive with the use of the word "end" as
        | the terminator for all types of block. In practice you
        | can lay it out like Python, and the "end"s help you keep
        | track when e.g. you need to place a single expression
        | after some deeply-nested blocks.
 
| solatic wrote:
| > Totality
| 
| Best of luck. Dhall is a current language with totality, but it
| runs into impossibly high memory requirements as a result. We had
| CI workers with 16 GB RAM run into out-of-memory issues because
| of the sheer size of the totally expanded type space (sum types
| of types which are themselves sum types of types which are
| themselves sum types etc... Exponential growth is easy).
| 
| I appreciate that this is scoped as a hobby project for now, not
| recommended for production, so like I said, best of luck :)
 
  | atennapel wrote:
  | I'm not sure what you mean with totally expanded type space.
  | But it sounds like Dhall has an issue with
  | unfolding/normalisation.
  | 
  | Totality shouldn't have any special impact on memory usage as
  | far as I know. It just restricts the kind of recursive
  | functions and data types you can write.
 
| iamwil wrote:
| What were the series of resources or readings that you did to
| help you create Tao?
 
  | zesterer wrote:
  | There wasn't really any single resource I read. Frustratingly,
  | I find it quite difficult to read research papers (I'm told
  | it's a skill acquired with practice, but it's something I've
  | never gotten into). Most of the implementation is the product
  | of several rewrites and false-starts, along with the occasional
  | hint I've read about here or there on the web.
 
| darthrupert wrote:
| Hardly ever is "good REPL" one of the features of these new
| languages. Do they think it's irrelevant or is making such a
| thing too difficult compared to all these more CSy features?
 
  | zesterer wrote:
  | REPLs are often difficult to reconcile with AoT compilation and
  | static analysis, particularly in the context of things like
  | type inference (at least, in a way that preserves semantics).
  | It's on my mental todo list, but not a priority for me.
 
    | pohl wrote:
    | Do you suppose that might be an outmoded historical bias? I'm
    | wondering if maybe the advancement of hardware has made it so
    | that the costs of AOT compilation and a type system should no
    | longer stand in the way of delivering a reasonable REPL
    | experience. Swift's "playgrounds" seems to do alright -- a
    | real outlier in this regard.
 
      | skavi wrote:
      | Haskell has a REPL. No idea whether it's considered good
      | though.
 
    | catlifeonmars wrote:
    | How fast is the compiler? In many cases a report can just be
    | syntactic sugar for compiling and running an accumulating log
    | of source code lines. It's not really important how it works
    | under the hood as long as it's mostly transparent to the
    | user.
    | 
    | As a side effect, it might also be a good way to keep your
    | compile times down.
 
      | substation13 wrote:
      | What if one of those lines fires the missiles?
 
      | zesterer wrote:
      | Fast enough for this approach to work for small examples.
      | For longer examples, I'm less confident: I've yet to
      | implement a proper module system (other than a slightly
      | more principled version of C's #include) so this currently
      | means compiling the entire standard library on every REPL
      | line. Thankfully, the compiler can still handle this within
      | about 100 milliseconds on my machine. Perhaps when I have a
      | more rugged module system I can look into this more, thanks
      | for the suggestion!
 
      | darthrupert wrote:
      | That's not even close to being adequate for the kinds of
      | things good REPLs are good for.
 
| shirogane86x wrote:
| This looks great! I've actually been experimenting with making a
| functional language too, in rust - so I'm probably gonna read
| through the code soon! Also, those error messages look really
| good - I'm totally gonna try ariadne and chumsky out :)
 
  | zesterer wrote:
  | Good luck! Feel free to open a discussion topic or issue if you
  | have any questions!
 
    | throwaway17_17 wrote:
    | Since someone brought it up, and since I don't speak rust...
    | are the error message formats (i.e. the lines and crossings)
    | made by a rust library or did you implement them? They are
    | certainly visually nice.
 
      | zesterer wrote:
      | They are made by a Rust library, but it's a library I wrote
      | for this project (now used by others too):
      | https://github.com/zesterer/ariadne
 
| magicalhippo wrote:
| Great readme, and definitely made me want to play with it. I was
| raised on procedural programming and never really got into proper
| functional programming, but somehow this just clicked for me.
 
| erezsh wrote:
| Asking as a complete newbie in this paradigm, but what's the
| benefit of writing factorial like this?                   fn
| factorial =              | 0 => 1             \ y ~ x + 1 => y *
| factorial(x)
| 
| Instead of                       | y => y * factorial(y-1)?
 
  | zesterer wrote:
  | Subtraction of natural numbers is non-total, and can result in
  | negative numbers, which cannot be represented as a natural
  | number. Most languages throw an exception, panic, etc. None of
  | these are solutions I'm happy with.
  | 
  | In Tao, natural numbers don't support subtraction but you can
  | decrement them by pattern-matching as in this example, allowing
  | the compiler to 'check your workings' and statically prove that
  | your program can never result in underflows.
  | 
  | In a similar vein, you can't index directly into a list
  | (because indexing is a fallible operation). Instead, you must
  | pattern-match on the list and explicitly handle the empty case
  | (you can also write a utility function to do this for you like
  | so)                   fn nth : Nat -> [A] -> Maybe A =
  | | _, [] => None             | 0, [x ..] => Just x             \
  | n + 1, [.. tail] => tail->nth(n)
  | 
  | Used like:                   [1, 2, 3]->nth(1) # Evaluates to
  | `Some 2`
 
| Akronymus wrote:
| A few observations:
| 
| Seems very ML/Haskell inspired.
| 
| All tuples seem to require parenthesis.
| 
| Definitely not ergonomic on a qwertz layout (Altough, what
| language is?)
| 
| No current plans for an interactive/repl version it seems
| 
| No dependant types either.
| 
| Overall, pretty interesting. Definitely warrants a closer look.
 
  | zesterer wrote:
  | Pretty much!
  | 
  | The language does support limited sugar for tuples without
  | parentheses in some specific cases, such as `match` and `let`:
  | let x, y = 5, 4 in         ...              match x, y in
  | | 4, 7 => None             \ _, y => Just y
  | 
  | However, these cases only incidentally lower to tuple pattern
  | matching, and deliberately hide the fact that tuples are used
  | internally.
 
    | Akronymus wrote:
    | Are you planning on having something similar to computation
    | expressions? Altough, I guess thats basically covered within
    | the do notation.
    | 
    | https://docs.microsoft.com/en-us/dotnet/fsharp/language-
    | refe...
 
      | zesterer wrote:
      | Yes! As you say, the do notation + monads covers this, but
      | I'm planning to remove it in favour of a slightly more
      | general 'effect basin' syntax that I'm currently working on
      | (syntactically similar to Rust's async + await, but
      | generalised to all effectful operations like mutation, IO,
      | etc.). Example here: https://github.com/zesterer/tao/blob/m
      | aster/examples/mutate....
 
  | platz wrote:
  | > No dependant types either.
  | 
  | You're funny
 
    | Akronymus wrote:
    | How so? I personally find dependant types to be very
    | interesting, but I get that they are a PITA to implement. So,
    | for me, it was simply an observation that there are currently
    | no plans for dependant types. No value judgement intended.
 
      | isaacimagine wrote:
      | Not to be pendantic, but I think you made a joke without
      | realizing it.
 
        | Akronymus wrote:
        | I did? I have now spent like 20 minutes trying to figure
        | it out. But I still don't get it.
 
        | macintux wrote:
        | I'm guessing it has something to do with the keyword
        | "either" and Haskell types, but I'm otherwise clueless.
        | Every time I look at Haskell I run the other way.
 
        | zesterer wrote:
        | I think it was "value judgement" (dependent types allow
        | dispatching over a value in the type system)
 
| maweki wrote:
| So is the language planned to be computationally complete or
| total?
| 
| I was not completely clear on your definition of totality. But I
| am all for not Turing-complete models of computation that still
| do useful things.
 
  | zesterer wrote:
  | For now, just total (i.e: functions can't panic, throw
  | exceptions, etc.). I'd like to explore termination analysis in
  | the future though!
 
    | samatman wrote:
    | It's an unfortunate conflation between total functions and
    | _total functional programming_ , which is done with non-
    | terminating languages. If I'm reading you right, Tao
    | currently requires functions to be total but is not designed
    | to always terminate.
 
      | zesterer wrote:
      | Yes. This is something I've been thinking about a lot, as
      | it happens! In particular, one of the great benefits of
      | pure languages from an optimisation standpoint is that
      | unused values can always be optimised away, but this is not
      | the case if we treat termination (or non-termination) as a
      | side effect! For now, I'm treating it as not being a side-
      | effect (as does C++, although C++ goes a step further and
      | treats it as straight-up UB in certain conditions). This is
      | something I've still yet to nail down semantically.
 
| zesterer wrote:
| Hey, author here. I definitely didn't expect to see Tao on Hacker
| News. As is probably obvious, the language is _extremely_ early
| in its life, and it 's not practical to write anything but
| trivial examples in it yet. Please don't judge!
 
  | agumonkey wrote:
  | good luck
 
  | code_biologist wrote:
  | I remember a golden age of programming reddit and HN in the
  | late 2000s that inspired me learn a bunch of new programming
  | languages, Haskell the biggest influence among them. It seemed
  | like people were always posting their own personal languages,
  | lisps (I remember the hot takes on Arc lol), and such all the
  | time. I have very fond memories of going through Jack
  | Crenshaw's "Let's Build a Compiler" after seeing it posted a
  | bunch of times, then trying to build my own language in a
  | similar vein.
  | 
  | Cheers to you, and I hope you're learning and having fun
  | working on your project!
 
    | zesterer wrote:
    | Thanks!
 
      | jrumbut wrote:
      | I too remember that time and it left me terribly jaded
      | about the utility of new languages.
      | 
      | This is the first I've seen in a while where I think the
      | offering hits a spot on the tradeoff continuum that is
      | distinctive and where I can picture many circumstances
      | where I would want to use this language (the soundness
      | aspect is a big part of that).
 
  | dmix wrote:
  | Nice work on the README. Gets right to the point about what it
  | look likes and what the goals are.
 
  | yccs27 wrote:
  | Tao looks super cool, and similar to the kind of language I'd
  | personally make if I decided to create one. Kudos for actually
  | implementing yours!
  | 
  | Some specific questions about the language design: - Does your
  | flavor of algebraic effects allow distinct effects of the same
  | type (e.g. two separate int-valued `State`s)? I haven't seen
  | anyone talk about this, but it seems like a potential problem
  | with effects.
  | 
  | - Do you have plans for making pattern matching extensible?
  | I've thought a lot about how this could be possible with optics
  | (the FP construction), but haven't found a nice solution yet.
 
    | zesterer wrote:
    | > Does your flavor of algebraic effects allow distinct
    | effects of the same type
    | 
    | Could you give an example of what you mean by this? Multiple
    | effects can be combined together (although I'm still working
    | on handlers for multiple effects), for example:
    | effect console = input + print              fn greet_user :
    | console ~ () = {             print("Please enter your
    | name:")!;             let name = input!;
    | print("Hello, " ++ name)!;         }
    | 
    | > Do you have plans for making pattern matching extensible?
    | 
    | I have no plans as of yet. Extensible pattern-matching seems
    | to me to be quite hard to unify with exhaustivity. Tao
    | supports most of the patterns that Rust/Haskell supports.
 
      | throwaway17_17 wrote:
      | I think GP is referring to having two effects, like State1
      | and State2, both of which allow for stateful effects on int
      | references, and then being able to handle the effects
      | uniquely for each effect. I think the underlying type
      | theoretical question would be are Tao's effects nominally
      | vs. structurally typed.
      | 
      | A more practical example would be having two state-like
      | effects for use as different allocation/deallocation
      | strategies.
 
        | zesterer wrote:
        | Tao's effects are nominally typed, so there's no way to
        | accidentally mix them up in the way I assume you're
        | describing. For example:                   # Define a new
        | effect that yields to the caller         effect yield A =
        | A => ()              # A generator that emits numbers
        | def one_two_three : yield Nat ~ () = {
        | yield(1)!;             yield(2)!;             yield(3)!;
        | }              # Print the numbers to the console
        | def main : io ~ () = {             one_two_three
        | handle yield Nat with n => print(n->show)!         }
 
  | roguas wrote:
  | Designing a PL is a hard complicated process, very slim portion
  | of professional programmers are able to deliver some novelty
  | here. I think any judgement should be treated as merely a
  | feedback on the usefulness of this language. The effort alone
  | is exceptional accomplishment. Take care.
 
    | zesterer wrote:
    | Thanks for your kind words :)
 
  | dataangel wrote:
  | > A rather dogged and obnoxious opinion of mine is that the
  | 'optimisation ceiling' for statically-typed, total functional
  | programming languages is significantly higher than traditional
  | imperative languages with comparably weak type systems.
  | 
  | Curious about plans for this. When Haskell use exploded I
  | followed a lot of the blogs talking about it someday being
  | faster than C because purity made compiler reasoning easier and
  | stream fusion and other things were going to change the world,
  | but as time went on idiomatic Haskell never came even close to
  | C. Now having a lot of performance experience I think a major
  | factor is that functional languages insist on using lists for
  | everything, which map poorly to hardware. Looking at your
  | screenshots, it looks like it still employs the list paradigm.
 
    | zesterer wrote:
    | So... I want to preface this by saying that I'm very, very
    | far from being an expert on this topic. Although Tao's
    | compiler has a MIR optimiser, it only covers the basics
    | (inlining, constant folding + symbolic execution, etc.).
    | 
    | I think one of the main reasons that Haskell failed to solve
    | this is actually the same reason that many lower level
    | languages failed: it places too many requirements on data
    | representation. In the case of C/C++ and even (to a lesser
    | extent) modern languages like Rust and Swift, this is because
    | they make promises about representation to the programmer
    | that allow you to circumvent aspects of the language and
    | still write correct code: be it transmutation, casting, field
    | offsets, etc. In the case of Haskell, lists have an entirely
    | arbitrary length and the language makes no effort to
    | constrain this requirement in the type system, meaning that
    | the compiler can only speculatively optimise a list into an
    | unboxed array. In a language with dependent types, it should
    | be possible to constrain the size of a list with the type
    | system, allowing the optimiser to do its job without need for
    | speculative whole-program analysis.
    | 
    | The other reason Haskell doesn't quite succeed is
    | monomorphisation (or lack thereof). Haskell's support for
    | first-class higher-ranked types means that the language can't
    | feasibly make promises about monomorphisation, and as a
    | result it needs to revert to boxing and dynamic dispatch far
    | more than it really should. Conversely, Tao is designed to
    | monomorphise in all cases from the start.
    | 
    | Rust demonstrates that functional programming (and in
    | particular, programming with higher-order functions) is more
    | than possible to optimise very well, and it does this by
    | promising monomorphisation through the type system, allowing
    | the compiler to aggressively perform static dispatch and
    | inlining.
    | 
    | From what I've seen, GHC also fails to pick a lot of low-
    | hanging fruit. The last time I checked (perhaps this has
    | since changed) GHC often struggles with things like TCO and
    | inlining in relatively simple cases as a byproduct of its
    | design (all functions are dynamically dispatched by default,
    | with inlining being a speculative optimisation).
    | 
    | I need to do a little more writing about exactly what ideas I
    | have for Tao, but other languages of similar ilk demonstrate
    | that Haskell is very far from the pinnacle of what is
    | possible (for example, Koka's Perceus reference reuse:
    | https://koka-lang.github.io/koka/doc/book.html#why-perceus).
 
      | shadowofneptune wrote:
      | > all functions are dynamically dispatched by default, with
      | inlining being a speculative optimisation
      | 
      | Could you please point me to other approaches to inlining?
      | I am also working on a personal language and it could be
      | helpful.
 
        | zesterer wrote:
        | Rust gives each closure a unique type (see the `Fn`
        | trait: https://doc.rust-lang.org/core/ops/trait.Fn.html),
        | allowing the compiler to always statically dispatch to
        | the exact function body at compile-time. That said, this
        | is a rather more explicit approach that won't necessarily
        | fit everything.
 
  | slavapestov wrote:
  | I'm curious how you implement associated types and equivalences
  | between them. In the most general case, this allows encoding an
  | arbitrary finitely-presented monoid in the type system, and the
  | word problem on finitely-presented monoids is undecidable.
  | However, you mention your type checker is Turing-complete.
 
    | zesterer wrote:
    | Yep, this is the case: the type-checker allows arbitrary
    | computation to occur at compilation time. You can see some of
    | that here, where I've implemented peano
    | arithmetic/addition/multiplication/branching using the type
    | system:
    | https://github.com/zesterer/tao/blob/master/examples/type-
    | as... . I've not yet had the time or mental fortitude to
    | implement something more non-trivial like N-queens or a
    | Brainfuck interpreter, but perhaps eventually!
 
| slewis wrote:
| Very cool! This might be a naive question. Are your arithmetic
| patterns equivalent to dependent types, like those found in
| Idris?
 
  | zesterer wrote:
  | They're more akin to 'destructuring' natural numbers into
  | successors. Consider:
  | 
  | data Nat = Zero | Succ Nat
  | 
  | You could pattern match on this Nat, fetching the inner Nat,
  | allowing the type system to prove that all cases are handled
  | exhaustively. Arithmetic patterns just extend this notion to
  | the built-in Nat type.
  | 
  | Full dependent typing is something I'd like to experiment with
  | in time, but I'm not there yet.
 
| schaefer wrote:
| The Tao that can be told is not the true Tao.
 
___________________________________________________________________
(page generated 2022-07-05 23:01 UTC)