其中name不在前一个where子句的范围内

时间:2017-01-30 08:39:49

标签: haskell scope 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

我错过了什么?

1 个答案:

答案 0 :(得分:3)

where子句绑定到单个模式匹配,而不是更宽。 绑定多个guard子句,例如:

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子句中的所有定义都可以看到所有绑定值,所以你的第一个等式将很乐意使用你上一个等式中定义的值。