typestar

grade_report.hs en Haskell

Promedia los puntajes de cada estudiante, asigna nota con letra e imprime una tabla ordenada con resumen del curso.

import Data.List (sortOn)
import Data.Ord (Down (..))

students :: [(String, [Int])]
students =
  [ ("Ada", [92, 88, 95, 79])
  , ("Bruno", [71, 64, 80, 77])
  , ("Chen", [88, 91, 84, 90])
  , ("Dara", [55, 48, 58, 51])
  , ("Esme", [100, 96, 93, 98])
  ]

-- An empty score list averages to zero rather than dividing by zero.
average :: [Int] -> Double
average [] = 0
average xs = fromIntegral (sum xs) / fromIntegral (length xs)

-- Guards read as a table of cutoffs, checked from the top down.
letterFor :: Double -> Char
letterFor avg
  | avg >= 90 = 'A'
  | avg >= 80 = 'B'
  | avg >= 70 = 'C'
  | avg >= 60 = 'D'
  | otherwise = 'F'

-- Round to one decimal by scaling into Int and splitting the digits.
oneDecimal :: Double -> String
oneDecimal x = show whole ++ "." ++ show frac
  where
    (whole, frac) = round (x * 10) `divMod` (10 :: Int)

pad :: Int -> String -> String
pad n s = s ++ replicate (n - length s) ' '

lpad :: Int -> String -> String
lpad n s = replicate (n - length s) ' ' ++ s

row :: (String, [Int]) -> String
row (name, scores) =
  pad 8 name ++ lpad 7 (oneDecimal avg) ++ lpad 7 [letterFor avg]
  where
    avg = average scores

rule :: String
rule = replicate 22 '-'

main :: IO ()
main = do
  let ranked = sortOn (Down . average . snd) students
      classAvg = average (concatMap snd students)
      passing = length [s | s <- students, average (snd s) >= 60]
  putStrLn "term grades, best first"
  putStrLn (pad 8 "student" ++ lpad 7 "average" ++ lpad 7 "grade")
  putStrLn rule
  mapM_ (putStrLn . row) ranked
  putStrLn rule
  putStrLn (pad 8 "class" ++ lpad 7 (oneDecimal classAvg)
              ++ lpad 7 [letterFor classAvg])
  putStrLn (show passing ++ " of " ++ show (length students) ++ " passing")

Cómo funciona

  1. average divide fromIntegral (sum xs) entre el conteo y responde cero para una lista vacía.
  2. letterFor elige la nota con guardas, probando primero avg >= 90 = 'A' y cayendo hasta otherwise.
  3. sortOn (Down . average . snd) pone al mejor primero, y oneDecimal redondea escalando a Int y partiendo con divMod.

Palabras clave y builtins usados aquí

El intento, en números

Líneas
60
Caracteres a escribir
1663
Tokens
419
Ritmo de tres estrellas
75 tpm

Al ritmo de tres estrellas de 75 tokens por minuto, este intento toma unos 335 segundos.

Escribe este fragmento

Paso 2 de 3 en Bis; paso 26 de 27 en Fundamentos del lenguaje.

← Anterior Siguiente →