Reputation: 31
Totally new to Haskell. Problem- I have a type constructor with a value constructor consisting of 4 components:
TrackPoint :: TP { rpm :: Integer
, time :: Integer
, distance :: Float
, speed :: Float
} deriving (Show)
I would like to take [TrackPoint] and have it return time, distance and speed anytime the rpm value is below 10,000. I have tried using guards with no luck. Any help would be appreciated by this novice.
Upvotes: 3
Views: 116
Reputation: 43309
Simple function:
processTrackPoints :: [TrackPoint] -> [(Integer, Float, Float)]
processTrackPoints tps =
map (\tp -> (time tp, distance tp, speed tp)) $
filter (\tp -> rpm tp > 10000) tps
Same, but point-free where possible:
processTrackPoints :: [TrackPoint] -> [(Integer, Float, Float)]
processTrackPoints =
map (\tp -> (time tp, distance tp, speed tp)) .
filter ((> 10000) . rpm)
Using guards:
processTrackPoints :: [TrackPoint] -> [(Integer, Float, Float)]
processTrackPoints ((TP rpm time distance speed) : t)
| rpm > 10000 = (time, distance, speed) : processTrackPoints t
| otherwise = processTrackPoints t
processTrackPoints _ = []
That is all, of course, assuming, that you have the datatype defined correctly like this:
data TrackPoint =
TP {
rpm :: Integer,
time :: Integer,
distance :: Float,
speed :: Float
}
deriving (Show)
Upvotes: 3
Reputation: 54971
It’s easy to do with comprehensions:
[ (time, distance, speed)
| TP rpm time distance speed <- trackPoints
, rpm < 10000
]
Even easier with {-# LANGUAGE RecordWildCards #-}
:
[ (time, distance, speed)
| TP{..} <- trackPoints
, rpm < 10000
]
The convention for records in Haskell is usually to prefix them to avoid name collisions, e.g., tpRpm
. It’s also worthwhile to remember that list comprehensions are just sugar for the list monad:
timesDistancesAndSpeedsOrSomeBetterName <- do
TP{..} <- trackPoints
guard (rpm < 10000)
return (time, distance, speed)
Upvotes: 1