Switch to no line breaks (for Ghostwriter support)
This commit is contained in:
parent
a95490d9d4
commit
2d9da2899f
|
@ -5,30 +5,17 @@ tags: ["C and C++", "Functional Languages", "Compilers"]
|
||||||
draft: true
|
draft: true
|
||||||
---
|
---
|
||||||
|
|
||||||
Now that our language's type system is more fleshed out and pleasant to use,
|
Now that our language's type system is more fleshed out and pleasant to use, it's time to shift our focus to the ergonomics of the language itself. I've been mentioning `let/in` expressions and __lambda expressions__ for a while now. The former will let us create names for expressions that are limited to a certain scope (without having to create global variable bindings), while the latter will allow us to create functions without giving them any name at all.
|
||||||
it's time to shift our focus to the ergonomics of the language itself. I've been
|
|
||||||
mentioning `let/in` expressions and __lambda expressions__ for a while now.
|
|
||||||
The former will let us create names for expressions that are limited to
|
|
||||||
a certain scope (without having to create global variable bindings), while
|
|
||||||
the latter will allow us to create functions without giving them any name at
|
|
||||||
all.
|
|
||||||
|
|
||||||
Let's take a look at `let/in` expressions first, to make sure we're all on
|
Let's take a look at `let/in` expressions first, to make sure we're all on the same page about what it is we're trying to implement. Let's start with some rather basic examples, and then move on to more complex examples. The most basic use of a `let/in` expression is, in Haskell:
|
||||||
the same page about what it is we're trying to implement. Let's
|
|
||||||
start with some rather basic examples, and then move on to more
|
|
||||||
complex examples. The most basic use of a `let/in` expression is, in Haskell:
|
|
||||||
|
|
||||||
```Haskell
|
```Haskell
|
||||||
let x = 5 in x + x
|
let x = 5 in x + x
|
||||||
```
|
```
|
||||||
|
|
||||||
In the above example, we bind the variable `x` to the value `5`, and then
|
In the above example, we bind the variable `x` to the value `5`, and then refer to `x` twice in the expression after the `in`. The whole snippet is one expression, evaluating to what the `in` part evaluates to. Additionally, the variable `x` does not escape the expression -
|
||||||
refer to `x` twice in the expression after the `in`. The whole snippet is one
|
|
||||||
expression, evaluating to what the `in` part evaluates to. Additionally,
|
|
||||||
the variable `x` does not escape the expression -
|
|
||||||
{{< sidenote "right" "used-note" "it cannot be used anywhere else." >}}
|
{{< sidenote "right" "used-note" "it cannot be used anywhere else." >}}
|
||||||
Unless, of course, you bind it elsewhere; naturally, using <code>x</code>
|
Unless, of course, you bind it elsewhere; naturally, using <code>x</code> here does not forbid you from re-using the variable.
|
||||||
here does not forbid you from re-using the variable.
|
|
||||||
{{< /sidenote >}}
|
{{< /sidenote >}}
|
||||||
|
|
||||||
Now, consider a slightly more complicated example:
|
Now, consider a slightly more complicated example:
|
||||||
|
@ -41,28 +28,14 @@ Here, we're defining a _function_ `sum`,
|
||||||
{{< sidenote "right" "eta-note" "which takes a single argument:" >}}
|
{{< sidenote "right" "eta-note" "which takes a single argument:" >}}
|
||||||
Those who favor the
|
Those who favor the
|
||||||
<a href="https://en.wikipedia.org/wiki/Tacit_programming#Functional_programming">point-free</a>
|
<a href="https://en.wikipedia.org/wiki/Tacit_programming#Functional_programming">point-free</a>
|
||||||
programming style may be slightly twitching right now, the words
|
programming style may be slightly twitching right now, the words <em>eta reduction</em> swirling in their mind. What do you know, <code>fold</code>-based <code>sum</code> is even one of the examples on the Wikipedia page! I assure you, I left the code as you see it deliberately, to demonstrate a principle.
|
||||||
<em>eta reduction</em> swirling in their mind. What do you know,
|
{{< /sidenote >}} the list to be summed. We will want this to be valid in our language, as well. We will soon see how this particular feature is related to lambda functions, and why I'm covering these two features in the same post.
|
||||||
<code>fold</code>-based <code>sum</code> is even one of the examples
|
|
||||||
on the Wikipedia page! I assure you, I left the code as you see it
|
|
||||||
deliberately, to demonstrate a principle.
|
|
||||||
{{< /sidenote >}} the list to be summed. We will want this to be valid
|
|
||||||
in our language, as well. We will soon see how this particular feature
|
|
||||||
is related to lambda functions, and why I'm covering these two features
|
|
||||||
in the same post.
|
|
||||||
|
|
||||||
Let's step up the difficulty a bit more, with an example that,
|
Let's step up the difficulty a bit more, with an example that,
|
||||||
{{< sidenote "left" "translate-note" "though it does not immediately translate to our language," >}}
|
{{< sidenote "left" "translate-note" "though it does not immediately translate to our language," >}}
|
||||||
The part that doesn't translate well is the whole deal with patterns in
|
The part that doesn't translate well is the whole deal with patterns in function arguments, as well as the notion of having more than one equation for a single function, as is the case with <code>safeTail</code>.
|
||||||
function arguments, as well as the notion of having more than one equation
|
|
||||||
for a single function, as is the case with <code>safeTail</code>.
|
|
||||||
<br><br>
|
<br><br>
|
||||||
It's not that these things are <em>impossible</em> to translate; it's just
|
It's not that these things are <em>impossible</em> to translate; it's just that translating them may be worthy of a post in and of itself, and would only serve to bloat and complicate this part. What can be implemented with pattern arguments can just as well be implemented using regular case expressions; I dare say most "big" functional languages actually just convert from the former to the latter as part of the compillation process.
|
||||||
that translating them may be worthy of a post in and of itself, and would only
|
|
||||||
serve to bloat and complicate this part. What can be implemented with
|
|
||||||
pattern arguments can just as well be implemented using regular case expressions;
|
|
||||||
I dare say most "big" functional languages actually just convert from the
|
|
||||||
former to the latter as part of the compillation process.
|
|
||||||
{{< /sidenote >}} illustrates another important principle:
|
{{< /sidenote >}} illustrates another important principle:
|
||||||
|
|
||||||
```Haskell
|
```Haskell
|
||||||
|
@ -75,11 +48,9 @@ in
|
||||||
myTail
|
myTail
|
||||||
```
|
```
|
||||||
|
|
||||||
The principle here is that definitions in `let/in` can be __recursive and
|
The principle here is that definitions in `let/in` can be __recursive and polymorphic__. Remember the note in
|
||||||
polymorphic__. Remember the note in
|
|
||||||
[part 10]({{< relref "10_compiler_polymorphism.md" >}}) about
|
[part 10]({{< relref "10_compiler_polymorphism.md" >}}) about
|
||||||
[let-polymorphism](https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system#Let-polymorphism)? This is it: we're allowing polymorphic variable bindings,
|
[let-polymorphism](https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system#Let-polymorphism)? This is it: we're allowing polymorphic variable bindings, but only when they're bound in a `let/in` expression (or at the top level).
|
||||||
but only when they're bound in a `let/in` expression (or at the top level).
|
|
||||||
|
|
||||||
The principles demonstrated by the last two snippets mean that compiling `let/in` expressions, at least with the power we want to give them, will require the same kind of dependency analysis we had to go through when we implemented polymorphically typed functions. That is, we will need to analyze which functions calls which other functions, and typecheck the callees before the callers. We will continue to represent callee-caller relationships using a dependency graph, in which nodes represent functions, and an edge from one function node to another means that the former function calls the latter. Below is an image of one such graph:
|
The principles demonstrated by the last two snippets mean that compiling `let/in` expressions, at least with the power we want to give them, will require the same kind of dependency analysis we had to go through when we implemented polymorphically typed functions. That is, we will need to analyze which functions calls which other functions, and typecheck the callees before the callers. We will continue to represent callee-caller relationships using a dependency graph, in which nodes represent functions, and an edge from one function node to another means that the former function calls the latter. Below is an image of one such graph:
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user