gleam icon indicating copy to clipboard operation
gleam copied to clipboard

Using curried functions with const

Open ghivert opened this issue 1 year ago • 2 comments

Hi! So happy to have a new functional programming language! I'm not sure where I'm supposed to ask, so I'm opening an issue here 🙂 Sorry for inconvenience if it's the wrong place, feel free to close the issue or anything and point me to the right place!

I'm trying to play with curried functions in Gleam, and I don't understand some design decisions. I can assign a function to a constant, but I can't assign a function return value to a constant.

fn example(a) {
  fn(b) {
    a + b
  }
}

const c = example(1) // This is not allowed
const d = example    // This is allowed

Here in both case, the code seems valid, but the first case is forbidden by the compiler. Is there any specific reason to not allow it? It seems to me like a logical case, and avoid something like :

fn example(a) {
  fn(b) {
    a + b
  }
}

fn c(b) {
  example(1, b)
}

ghivert avatar Mar 19 '24 23:03 ghivert

I believe the issue you are running into is with what the const keyword is doing. const values need to be known (and I believe are inlined?) at compile time so calling a function is not allowed. The error message is definitely confusing/misleading in this case (it looks like Gleam treats this as an invalid syntax error). Gleam doesn't have any special behavior about currying/curried functions (i.e. Gleam does not automatically curry functions in any way). So to run the example you have you would want to use let bindings within a function declaration like this:

import gleam/io

fn example(a) {
  fn(b) { a + b }
}

pub fn main() {
  let c = example(1)
  let d = example
  io.debug(c(2)) // 3
  io.debug(d(3)(4)) // 7
}

Acepie avatar Mar 20 '24 00:03 Acepie

Oh, I get your point. So as I was expecting, const is a special thing in the compiler, and I was wondering if it could come from some Erlang interop or anything else.

Actually, the pattern with curried function is something I use oftentimes (I'm coming from a Haskell/Elm/PureScript background for context) when I want to hide some configurations in child functions. For example, when dealing with flex items in frontend, I could have a function named flex not exposed, and two functions row and column defining some configuration and reusing flex (because in the end, it's the same thing in the browser).

fn flex(direction: String) {
  fn (children: List(Element(a))) {
    // Render the correct HTML here.
  }
}

pub const row = flex("row")
pub const column = flex("column")

And in such case, the idea is to expose only the last functions, and hide everything else. But I suppose I have to use the first version I wrote earlier, with fn row(children) { flex("row", children) } instead of using curried functions.

ghivert avatar Mar 20 '24 00:03 ghivert

Gleam isn't a scripting language, a language with compile time code execution, or a language with call-by-need evaluation, so there's no way to evaluate code in constants. Only literals are possible.

lpil avatar Mar 21 '24 13:03 lpil