Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 94 additions & 5 deletions src/content/docs/syntax/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,18 @@ title: Functions
description: Functions in Gren
---

A function returns different values depending on its input. In Gren, a function will always return the same result if provided the same input.
If constants allow you to give a name to a value, a function allows you to give a name to a calculation that produces a value. Functions take one or more inputs and return a single value.

```elm
addOne number =
number + 1
```

`addOne` is the name of the function and it is defined as being `number + 1`. If you do something like `result = addOne 7` then `result` will equal 8.

Very importantly and _very different_ from most other programming lanagues in Gren, a function will always return the same result if provided the same input. This might seem obvious for something like `addOne` but it's also true of things such as updating a complex bit of state in an application or even making a HTTP request. We'll get into `Command` and how Gren accomplishes this in a later section, for now it's enough just to know that Gren makes the guarantee that given the same input to a function, you will always get the same result.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love the changes and expansion on this explanation of what a function is in Gren. Some feedback on this paragraph in particular:

Very importantly and very different from most other programming lanagues in Gren, a function will always return the same result...

I don't like to assume people are always coming from mainstream languages when teaching Gren and don't want to repeatedly frame things in terms of how it's different from "most languages". I don't think the comparison is needed anyway and it's enough to say "Very importantly, in Gren, a function will always...". Especially since you touch on how it's obvious for this function but maybe not for other types of functions.

We'll get into Command and how Gren accomplishes this in a later section

Might be too soon to mention Command. What if you just say "We'll get into how Gren accomplishes this in a later section"?


Ok now let's see what a function that has more than one argument looks like.

```elm
sumOf first second =
Expand All @@ -13,9 +24,9 @@ sumOfFiveAndTwo =
sumOf 5 2
```

Here, `sumOf` is the name of the function, while `first` and `second` are the inputs to the function. The return value of `sumOf` is the last computed expression. In this case, the only expression is `first + second`, the result of which becomes the returned value.
Here, `sumOf` is the name of the function, while `first` and `second` are the inputs to the function. If you are familiar with another programming language you may have noticed the absence of any sort of `return` statement. That's because in Gren everything is an expression. The body of a function is just a single expression too. In this case, the expression is `first + second`, the result of which becomes the returned value. Of if you want to make more complex functions it is very handy to be able to carry out the work in a step-by-step way. The `let` keyword allows this and is discussed in a later section.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of if you want to make more complex functions it is very handy to be able to carry out the work in a step-by-step way. The let keyword allows this and is discussed in a later section

Typo on that first word (should be "Or"?) but I think this would read better if the "Or" was removed and the sentences were condensed to:

If you want to write a more complex function in a step-by-step way, the let keyword allows for this and is covered in a later section.


Functions can take an arbitrary number of arguments, but must return exactly one value.
Functions can take an arbitrary number of arguments, but return exactly one value.

Function arguments can be passed on multiple lines:

Expand All @@ -30,7 +41,7 @@ It looks kind of silly here, but it is helpful to know this when you’re readin

## Function Pipelines

You can chain multiple function calls with parenthesis:
When you need the result of one function as an input to another, you can use parenthesis to indicate this:

```elm
multiply first second =
Expand All @@ -39,8 +50,9 @@ multiply first second =
secondsInYear =
multiply 365 (multiply 24 (multiply 60 60))
```
Here the result of `multiply 60 60` becomes the second argument to `multiply 24` and the result of THAT becomes the second argument to `multiply 365`. This "inside-out" nesting is common in other programming languages and it works the same here, but Gren has a way of making this kind of chaining really nice to read.

But you can make this more readable with the `|>` operator:
We can make the above expression more readable with the `|>` operator:

```elm
secondsInYear =
Expand All @@ -53,6 +65,83 @@ secondsInYear =
`|>` passes the value on the left as the last argument to the function on the right.
For example `sumOf 1 2 |> multiply 3` is the same as `multiply 3 (sumOf 1 2)`.

## Function type signatures
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We haven't covered types at this point in the book so I think this section is premature. Perhaps it could be worked into the Types page? Function type signatures are introduced there.


Gren is really great at inferring the types for your functions but it's often helpful to put an explicit type declaration on your function. This can serve as documentation as well as helping you to isolate type checking problems. Adding a type signature to the multiply function from above would look like this:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

helping you to isolate type checking problems

I don't want to assume people are even familiar with the concept of "type checking" yet. What if this said "helping the compiler give you better error messages" or something along those lines?


```elm
multiply : Int -> Int -> Int
multiply first second =
first * second
```

What this type says is "multiply is a function that takes an Int and an Int as input, and returns an Int". You may notice that the symbol between the two arguments is the same as the symbol before the return type. This is not a coincidence. What's happening here is that functions in Gren always take their arguments one at a time. When we do `multiply 60 24` we're actually doing this `((multiply 60) 24)`. First the argument `60` is applied, then the argument `24`. So what would happen if we only provided one of the arguments? If you're used to how other programming languages work you might expect this to be an error, but in Gren it is not!
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love this explanation of partial application. I think the second half gets a little confusing though. Starting here:

First the argument 60 is applied, then the argument 24...

My suggestion:

First the argument 60 is applied, then the argument 24 is applied to the result of that. But what is the result of multiply 60? You might think it's an error, but in Gren it is not!


`oneArgument = multiply 24`
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you start with multiply 60 in the text above, maybe better to use 60 instead of 24 in this and the following examples.


So what is the type of `oneArgument`? It's not `Int` since that would be the result of providing both arguments. If we line up the one argument with the type signature it gives us a clue.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to give this some thought but my initial reaction was that framing this in terms of type signatures and lining up the arguments is confusing. I have a video where I tried to explain the concept here. If you want to take a look maybe we can come up with the best way to explain this together.


```elm
multiply: Int -> Int -> Int
multiply 24
```

what's left is the remaining part of the type signature, `Int -> Int` meaning that `oneArgument` has the type `Int -> Int`. This is called partial application and allows us to build up all the arguments for a function one at a time. This is what was going on in the function pipeline example before.

```elm
secondsInYear =
60 -- Int
|> multiply 60 -- Int -> Int
|> multiply 24 -- Int -> Int
|> multiply 365 -- Int -> Int
```

`multiply` is a function of type `Int -> Int -> Int` but `multiply 60` partially applies it, leaving us with just `Int -> Int`. The `|>` operator provides `60` as the second argument so now we have a fully applied function and we get the resulting `Int` which gets passed along by the next `|>` to `multiply 24` which is also of type `Int -> Int` and so on.

What's really going on under the hood is that `multiply` is actually a function that has this type: `multiply: Int -> (Int -> Int)` meaning "multiply is a function that takes an `Int` and returns a function of type `Int -> Int`. So when we say `multiply 24 60` we're first applying the 24, getting back the resulting function which is `Int -> Int`, then applying the 60 to that function to get the final Int.

```elm
multiply : Int -> (Int -> Int)
multiply 24

result : Int -> Int
60

result : Int
1440
```

Functions that take one argument at a time like this are known as `curried` functions. In some languages you can make functions be curried but you have to do it yourself, in Gren it's automatic.

The one place that curried functions might cause you trouble is when you don't give a function the correct number of arguments by mistake. Let's say you're using a function like this

```elm
validateUser : User -> Email -> DateTime -> Flags -> Status
```
That's a lot of arguments and you might easily forget one of them.

```elm
validateUser : User -> Email -> DateTime -> Flags -> Status
userStatus = validateUser user currentEmail now
```
`userStatus` is not a value of type `Status` it is a function of type `Flags -> Status`. It can be confusing when you go to compare `userStatus` with a `Status` like this `if userStatus == LoggedIn then` and get an error:

```
TYPE MISMATCH - I need both sides of (==) to be the same type:

1| if userStatus == LoggedIn then
#^^^^^^^^^^^^^^^^^^^^#
The left side of (==) is:
#Flags -> Status#

But the right side is:
Status
```

Fortunately Gren's error messages are very descriptive so you can more easily work out what has gone wrong.



## Anonymous Functions

You can create functions without giving them a name:
Expand Down