我读到没有语句,只有 Haskell 中的表达式。我认为表达式是评估(减少)为值的东西。1 + 1是一种表达,对吧?它减少到2,但单独一个数字怎么样:8?是8单独也被认为是一种表达?一个不再减少的表达式?我将不胜感激任何澄清。
是的,1 + 1是一种表达。是的,8是一种表达。是否8进一步减少是一个稍微复杂的问题,只是因为 Haskell 的一个奇怪的细节:数字是多态的。在像Intand这样的常见类型中Double,8不会有意义地减少;但是可以添加一个用户制作的实例,8可以进一步减少。
...但这些都是令人讨厌的语言律师-y 狡辩。从大局来看,你所说的一切基本上都是正确的。
我读到没有语句,只有 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
在函数体之外,语言中有很多东西不是表达式;在上面的例子中,以下不是表达式:
{-# LANGUAGE OverloadedStrings #-}(语言语用)module Main (main) where(一个模块,导出列表)import Web.Scotty(进口申报)main :: IO ()(类型签名)main =(顶部声明,或值绑定)其中,我认为import Web.Scotty可以称为一种语句,因为在语法上它是命令式的,但如果我们不精确,我更愿意将它们称为所有声明。
更有趣的是,在 Haskell 中,您既有值级别的表达式语言,也有类型级别的表达式语言。所以IO ()不是值表达式,而是类型表达式。如果您有能力将这两种表达式语言混合在一起,您就会拥有依赖类型。