Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is an expression in Haskell?

Tags:

haskell

I read that there are no statements, just expressions in Haskell. I think an expression is something that evaluates (reduces) to a value. 1 + 1 is an expression, right? It reduces to 2, but how about a number alone: 8? Is that 8 alone also considered to be an expression? An expression that doesn't reduce any further? I would be grateful for any clarification.

like image 276
Zoltan King Avatar asked Jul 28 '20 23:07

Zoltan King


People also ask

Is everything an expression in Haskell?

In fact, Haskell takes this principle to the extreme: everything in Haskell is an expression, and even statements are expressions. For example, the following code might appear to be a traditional imperative-style sequence of statements: main = do putStrLn "Enter a number:" -- Statement?

What is a case expression in Haskell?

The case expression in Haskell Many imperative languages have Switch case syntax: we take a variable and execute blocks of code for specific values of that variable. We might also include a catch-all block of code in case the variable has some value for which we didn't set up a case.

How are Haskell expressions evaluated?

An expression is evaluated by normal order (leftmost outermost redex first).

What is guard expression in Haskell?

A guard is basically a boolean expression. If it evaluates to True, then the corresponding function body is used. If it evaluates to False, checking drops through to the next guard and so on. If we call this function with 24.3, it will first check if that's smaller than or equal to 18.5.


2 Answers

Yes, 1 + 1 is an expression. Yes, 8 is an expression. Whether 8 reduces further is a slightly complicated question, just because of a strange detail of Haskell: numbers are polymorphic. At the usual types like Int and Double, 8 does not reduce meaningfully; but one could add a user-made instance where 8 could reduce further.

...but those are sort of annoying language-lawyer-y quibbles. In the big picture, everything you said is essentially right.

like image 59
Daniel Wagner Avatar answered Oct 18 '22 01:10

Daniel Wagner


I read that there are no statements, just expressions in Haskell.

To elaborate on @amalloy's comments about there being more than expressions in Haskell: You normally make the distinction between statements and expressions in imperative languages because you have something like x = 2 + 2; with the x = ...; part being a statement and the 2 + 2 part being an expression.

The body of a Haskell function is always one single expression (although with where you can split that one expression apart for convenience), and this is the main distinction that drives the question. So if you want to "do more than one thing", which is an imperative notion of a function being able to change global state, you solve this with monads, like so:

{-# LANGUAGE OverloadedStrings #-}
module Main (main) where
import Web.Scotty

main :: IO ()
main = scotty 3000 $
  get "/:who" $ do
    who <- param "who"
    text ("Beam " <> who <> " up, Scotty!")

Here, main's body (a monadic action, not a function) is a single expression, scotty 3000 (...). While the linebreak after scotty 3000 $ doesn't carry meaning and only makes the code look nicer, the linebreak in the do block actually reduces multiple actions into one expression via syntactic sugar. So while it may seem that this event handler does two things things: (1) param "who", (2) text (...), it is still one expression equivalent to this:

main =
  scotty 3000 (get "/:who" (param "who" >>= (\who -> text ("Beam " <> who <> " up, Scotty!"))))

with >>= being the invisible operator between the do-block lines. When expressions begin to grow, this becomes very inconvenient, so you split parts of them into sub-expressions and give those names, e.g. like:

main = scotty 3000 handler
  where
    handler = do
      get "/:who" getWho
      post "/" postWho

    getWho = do
      ...

    postWho = do
      ...

But it is essentially equivalent to one big expression.

This is the point where some people think they should make their own web-framework. :-D

There are many things in the language beyond function bodies that are not expressions; in the example above, the following are not expressions:

  • {-# LANGUAGE OverloadedStrings #-} (a language pragma)
  • module Main (main) where (a module, export list)
  • import Web.Scotty (an import declaration)
  • main :: IO () (a type signature)
  • main = (a top declaration, or a value binding)

Of these, I think import Web.Scotty could be called a kind of statement, since grammatically it's in imperative form, but if we're going to be imprecise, I'd prefer to call them all declarations.

More interestingly, in Haskell you have both an expression language at the value level and one at the type level. So IO () isn't a value expression, but it's a type expression. If you had the ability to mix those two expression languages up, you'd have dependent types.

like image 27
sshine Avatar answered Oct 18 '22 01:10

sshine