第二个 where name 不在前一个 where 子句的范围内

second where name is not in scope of the previous where clause

我定义了一个定义名称的地方earthSecondsAYear。遗憾的是,它不在前面的 where 子句的范围内。

代码如下:

module SpaceAge (Planet(..), ageOn) where

data Planet = Mercury
            | Venus
            | Earth
            | Mars
            | Jupiter
            | Saturn
            | Uranus
            | Neptune

ageOn :: Planet -> Float -> Float
ageOn planet seconds = (seconds / 100) * planetYearSecs planet
 where planetYearSecs Mercury = (earthSecondsAYear / 100) * 0.2408
       planetYearSecs Venus = 0.6151
       planetYearSecs Mars = 1.8808
       planetYearSecs Jupiter = 11.8626
       planetYearSecs Saturn = 29.4474
       planetYearSecs Uranus = 84.0168
       planetYearSecs Neptune = 164.7913
       planetYearSecs Earth = 100
         where earthSecondsAYear = 31557600

错误信息:

:14:34: error:
    Variable not in scope: earthSecondsAYear

我错过了什么?

一个 where 子句绑定到单个 pattern-match,并且没有更宽的范围。它确实 绑定多个保护子句,例如 in:

foo :: Int -> Int
foo 0 = 0
foo x | y < 30 = 5
      | otherwise = y
  where y = x * x

这可能会让您认为它适用于整个函数定义。但是你不能在这里的第一个等式中使用 y ,就像你不能在问题的第一个等式中使用 earthSecondsAYear 一样,因为你只将它绑定到最后一个等式。

但是,解决方法很简单:无需引入新的 where 子句,只需在现有的 where 子句中添加另一个定义即可:

ageOn :: Planet -> Float -> Float
ageOn planet seconds = (seconds / 100) * planetYearSecs planet
 where planetYearSecs Mercury = (earthSecondsAYear / 100) * 0.2408
       planetYearSecs Venus = 0.6151
       planetYearSecs Mars = 1.8808
       planetYearSecs Jupiter = 11.8626
       planetYearSecs Saturn = 29.4474
       planetYearSecs Uranus = 84.0168
       planetYearSecs Neptune = 164.7913
       planetYearSecs Earth = 100
       earthSecondsAYear = 31557600

where 子句中定义多个绑定是完全合法的,只需将它们缩进到同一级别即可。当您这样做时,where 子句内的所有定义都可以看到所有绑定值,因此您的第一个等式将愉快地使用上一个等式中定义的值。