【问题标题】:Forcing eager evaluation of a Haskell list强制对 Haskell 列表进行热切评估
【发布时间】:2015-07-26 09:11:39
【问题描述】:

翻阅“自学...”一书时,我遇到了一个 BMI 计算器应用程序。到目前为止,该应用程序需要一个 Double 对列表并返回一个 Double 列表:

calcBMI :: [(Double, Double)] -> [Dobule]
calcBMI xs = [bmi w h | (w, h) <- xs]
    where bmi weight height = weight / height ^ 2

尝试对返回列表的每个元素应用另一个函数我尝试了map declareBMI head calcBMI [(w, h) | w &lt;- [60..70], h &lt;- [1.65]],但出现错误(其中定义了declareBMI):

declareBMI :: Double -> String
declareBMI bmi
    | bmi <= 18.5 = "Skinny"
    | bmi <= 25 = "Norm"
    | bmi <=30 = "Overweight"
    | otherwise = "OBESE!"

查看map(即map f x:xs = f x : map f xs)的定义后,我发现了问题:我试图在lazy列表的其余部分调用head,意思是解释器尝试首先运行calcBMI,然后才运行head-ing 结果...这当然会失败,因为calcBMI 需要一个配对列表。

所以,我的问题是

  1. 有没有办法强制对 calcBMI 函数进行热切评估,以便我可以在结果列表上运行 head
  2. 有没有更好的方法然后强制热切评估以允许我head 结果列表的每个元素?

【问题讨论】:

  • map head calcBMI [(w, h) | w &lt;- [60..70], h &lt;- [1.65]] 只是类型错误,所以懒惰在这里并不是特别重要。此外,由calcBMI 生成的列表具有[Double] 类型,因此不可能head 每个元素,因为head 适用于列表而Double-s 不是列表。您能否说明您想要实现的功能?
  • 嗨。我想得到的结果是我运行另一个函数,比如 declareBMI,它采用数值 calcBMI 计算并输出一个字符串,上面写着“你没事”、“你很胖”等。据我所知calcBMI,正如我定义的那样,它返回一个 Double 列表:[Double]。我知道为什么map head 不起作用...现在我想了想,但我也尝试过:map declareBMI head calcBMI...,它也失败了。
  • 重新思考我的代码我明白为什么map不是正确的方法,从第二个元素开始,head 没有任何内容,它的输入错误为安德拉斯·科瓦奇说!所以,我现在完全不知道如何从双打列表中生成声明列表。

标签: haskell recursion lazy-evaluation


【解决方案1】:

确保类型对齐。如果您不确定类型或遇到编译器错误,请尝试将代码分解为更小的表达式并使用 GHCi 或 TypedHoles 来检查类型。

GHCi 会话示例:

> let xs = [(w, h) | w <- [60..70], h <- [1.65]]
> :t calcBMI xs
calcBMI xs :: [Double]

这里我们询问了calcBMI xs的类型,果然得到了[Double]

现在我们可以使用head 获取calcBMI xs 的第一个元素:

> head (calcBMI xs)
22.03856749311295

我们可以使用head,因为它的输入是一个列表,而calcBMI xs是一个列表。

> :t head
head :: [a] -> a

declareBMI 具有 Double -&gt; String 类型,因此我们可以将它用于普通的 Double 值,但我们也可以将它用于带有 map 的列表内的值。

> let bmis = calcBMI xs
> declareBMI (head bmis)
"Norm"

在这里,我们在Double 上使用了declareBMI。我们也可以先在列表元素上使用declareBMI,然后再应用head

> :t map declareBMI bmis
map declareBMI bmis :: [String]
> map declareBMI bmis
["Norm","Norm","Norm","Norm","Norm","Norm","Norm","Norm","Norm","Overweight","Overweight"]
> head (map declareBMI bmis)
"Norm"

另外,不要忘记在 Haskell 中我们仅通过空格来应用函数。所以head (map declareBMI bmis) 是正确的,因为map 这里有两个参数,head 有一个。我们不给函数调用加上括号,而是给函数的单个参数加上括号。

【讨论】:

  • 太棒了!非常感谢你。感谢您引导我完成它,而不仅仅是输入一些代码并让我弄清楚。另外,请对括号发表评论 - 牢记在心。
猜你喜欢
  • 2023-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-07
  • 2012-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多