Haskell 中的表达式是什么?

Zol*_*ing 8 haskell

我读到没有语句,只有 Haskell 中的表达式。我认为表达式是评估(减少)为值的东西。1 + 1是一种表达,对吧?它减少到2,但单独一个数字怎么样:8?是8单独也被认为是一种表达?一个不再减少的表达式?我将不胜感激任何澄清。

Dan*_*ner 8

是的,1 + 1是一种表达。是的,8是一种表达。是否8进一步减少是一个稍微复杂的问题,只是因为 Haskell 的一个奇怪的细节:数字是多态的。在像Intand这样的常见类型中Double8不会有意义地减少;但是可以添加一个用户制作的实例,8可以进一步减少。

...但这些都是令人讨厌的语言律师-y 狡辩。从大局来看,你所说的一切基本上都是正确的。


Sim*_*ine 5

我读到没有语句,只有 Haskell 中的表达式。

详细说明@amalloy 关于 Haskell 中不仅仅是表达式的评论:您通常会区分命令式语言中的语句和表达式,因为您有类似x = 2 + 2;x = ...;部分是语句和2 + 2部分是表达式。

Haskell 函数的主体始终是一个单独的表达式(尽管where为了方便您可以将那个表达式分开),这是驱动问题的主要区别。所以如果你想“做不止一件事”,这是一个函数能够改变全局状态的必要概念,你可以用 monads 解决这个问题,如下所示:

{-# 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!")
Run Code Online (Sandbox Code Playgroud)

这里,main的主体(一元操作,不是函数)是单个表达式,scotty 3000 (...)。虽然后面的换行符scotty 3000 $没有任何意义,只会让代码看起来更好看,但do块中的换行符实际上通过语法糖将多个操作简化为一个表达式。因此,虽然这个事件处理程序似乎做了两件事: (1) param "who", (2) text (...),但它仍然是一个等价于以下的表达式:

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

>>=作为invisible operator之间do嵌段线。当表达式开始增长时,这变得非常不方便,因此您将它们的一部分拆分为子表达式并给出这些名称,例如:

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

    getWho = do
      ...

    postWho = do
      ...
Run Code Online (Sandbox Code Playgroud)

但它本质上相当于一个大表达式。

这就是一些人认为他们应该制作自己的网络框架的地方。:-D

在函数体之外,语言中有很多东西不是表达式;在上面的例子中,以下不是表达式:

其中,我认为import Web.Scotty可以称为一种语句,因为在语法上它是命令式的,但如果我们不精确,我更愿意将它们称为所有声明

更有趣的是,在 Haskell 中,您既有值级别的表达式语言,有类型级别的表达式语言。所以IO ()不是值表达式,而是类型表达式。如果您有能力将这两种表达式语言混合在一起,您就会拥有依赖类型