首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在Haskell中,如何从整数列表中获得平均浮点数?

在Haskell中,如何从整数列表中获得平均浮点数?
EN

Stack Overflow用户
提问于 2020-04-22 20:23:59
回答 3查看 287关注 0票数 0

我已经编写了一个简单的函数来显示:地名、北度、东度和降雨量列表。

如何获得某个地方的平均降雨量?例如,在我的代码中,如何获得伦敦的平均降雨量?

抱歉,如果我的代码不是最好的,我只是在学习Haskell。

代码语言:javascript
运行
复制
import Data.Char
import Data.List
type Place = (String, Float, Float, [Int])

testData :: [Place]
testData = [("London", 51.5, -0.1, [0, 0, 5, 8, 8, 0, 0]),
            ("Cardiff", 51.5, -3.2, [12, 8, 15, 0, 0, 0, 2]),
            ("Norwich", 52.6, 1.3, [0, 6, 5, 0, 0, 0, 3])]

rainLevels :: [Place] -> Float 
rainLevels level (_, _, _, numbers) = sum numbers / 7
EN

回答 3

Stack Overflow用户

发布于 2020-04-23 06:48:53

要找到“伦敦”的平均降雨量,首先需要在列表中找到“伦敦”的记录,然后求其降雨量的平均值。

getAvgRainLevel使用一个特定城市的名称:name,以及一个记录列表:xs;它通过name查找该城市的记录,然后计算该城市的平均降雨量。

代码语言:javascript
运行
复制
getAvgRainLevel name xs = fmap avg $ lookup name (sanitize xs)
  where
    sanitize = fmap (\(city, _, _, rainLevels) -> (city, rainLevels))
    avg = (/) <$> sum <*>  fromIntegral . length
票数 2
EN

Stack Overflow用户

发布于 2020-04-22 20:49:07

如果你想在Haskell中除以Ints,你首先必须将它们转换成Floats,这样就避免了在其他静态类型语言中遇到的除法问题,比如C,其中5/22

那么,如何将Int转换为Float呢?有许多函数可以做到这一点,但最典型的选择是fromIntegral

代码语言:javascript
运行
复制
fromIntegral :: (Num b, Integral a) => a -> b

这会将任何整数类型转换为任何数值类型。因此,如果需要将[Int]转换为[Float]

代码语言:javascript
运行
复制
fmap fromIntegral :: (Functor f, Num b, Integral a) => f a -> f b

还有另外几个问题。您的代码不会按原样编译。您已经将函数rainLevels声明为只接受一个参数,但是在定义它时,您需要对两个参数进行模式匹配。按照目前的定义,rainLevels的实际类型是:

代码语言:javascript
运行
复制
rainLevels :: (Frac e) => a -> (b, c, d, [e]) -> e

Place(b, c, d, [e])匹配,但不使用约束(Frac e),这是fromIntegral将解决的问题,但您仍然会遇到[Place]不会在(_, _, _, numbers)上模式匹配的问题。由于我的读心术已经不幸失效,我留给您来决定rainLevels是要接受一个Place还是一个列表,但无论哪种方式,您都需要使签名与定义相匹配。

票数 1
EN

Stack Overflow用户

发布于 2020-04-22 23:10:31

除了对Andrew Ray的解释之外,我认为用代码提供一个可用的示例可能会有所帮助:

代码语言:javascript
运行
复制
module Lib
    ( avgRainLevel
    , rainLevels
    , testData
    ) where

import Data.Char
import Data.List
type Place = (String, Float, Float, [Int])

testData :: [Place]
testData = [("London", 51.5, -0.1, [0, 0, 5, 8, 8, 0, 0]),
            ("Cardiff", 51.5, -3.2, [12, 8, 15, 0, 0, 0, 2]),
            ("Norwich", 52.6, 1.3, [0, 6, 5, 0, 0, 0, 3])]

findPlace :: [Place] -> String -> Place
findPlace placeList place = head . filter isPlace $ placeList
  where isPlace (name, _, _, _) = name == place

getLevel :: Place -> [Int]
getLevel (_, _, _, levels) = levels

rainLevels :: [Place] -> String -> [Int]
rainLevels placeList place = getLevel $ findPlace placeList place

average :: [Int] -> Float
average ints = fromIntegral levelSum / fromIntegral count
  where levelSum = sum ints
        count = length ints

avgRainLevel :: [Place] -> String -> Float
avgRainLevel placeList place = average $ rainLevels placeList place

我有点不确定你想要得到的实际值是什么。根据名称rainLevels,我得出的结论是您需要雨量列表,因此我将类型调整为[Int]。因为您不仅提供了位置列表,还提供了要查询的实际位置,所以我必须添加另一个参数,该参数将一个-> String添加到函数的类型声明中。

基于该函数,我执行了另一个函数avgRainLevel,它计算类型为[Int]的列表中的值的平均值。

代码将会像文档中描述的那样使用这些测试:

代码语言:javascript
运行
复制
import Lib (rainLevels, avgRainLevel, testData)
import Test.Hspec (Spec, it, shouldBe)
import Test.Hspec.Runner (configFastFail, defaultConfig, hspecWith)

main :: IO ()
main = hspecWith defaultConfig {configFastFail = True} specs

specs :: Spec
specs = do

  it "can read the list of levels" $ do
    let levels = rainLevels testData "London"
    levels `shouldBe` [0, 0, 5, 8, 8, 0, 0]

  it "can calculate the average rain level" $ do
    let avg = avgRainLevel testData "Norwich"
    avg `shouldBe` 2

请注意,实际上您不应该从这两个函数中的任何一个返回[Int]Float。当您查询一个不在位置列表中的位置时,该代码将会死机。你最好返回Maybe [Int]Maybe Float。在这种情况下,当您没有关于给定地点的信息时,可以返回Nothing

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61365035

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档