Haskell-阅读人员列表

时间:2019-01-05 22:52:40

标签: haskell io

问题听起来像这样:编写一个程序,先读取n个数字,然后读取n个数字,然后每个人读取他们的姓名和年龄,然后返回年龄最大的一个人。

示例输入:

3
Ion Ionel Ionescu
70
Gica Petrescu
99
Mustafa ben Muhamad
7

示例输出

Oldest is Gica Petrescu (99 years).

到目前为止,我的代码:

readPers :: IO(String, Int)
readPers = do
    name <- getLine
    age <- readLn :: IO Int
    return (name, age)

readPerss :: (Ord t, Num t) => t -> [IO (String, Int)]
readPerss n
    | n > 0 = readPers : readPerss(n-1)
    | otherwise = []

pFunc = do
    print "Numer of persons:"
    n <- readLn :: IO Int
    let persons = readPerss n
    return persons

我先读n,然后尝试使用readPers和readPerss列出人员列表,但我被困住了,从那时起我不知道如何解决这个问题,我想到目前为止我的实现还不是非常正确。

我应该如何解决问题?

2 个答案:

答案 0 :(得分:3)

您非常亲密!您在readPerss :: (Ord t, Num t) => t -> [IO (String, Int)]中所做的工作将返回IO操作的列表;每个动作在执行时都会返回一对StringInt。当前在pFunc中,您只是构建这个动作列表,将其存储在带有let的变量中,然后从pFunc返回它;您永远不会使用<-“ bind”语句执行

有几种简单的方法可以执行所需的操作。对您的代码所做的最小更改就是添加sequence,它需要一个动作容器,并生成一个返回容器的动作:< / p>

sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)

这里t[]mIOa(String, Int)

sequence :: [IO (String, Int)] -> IO [(String, Int)]

另一种方法是重写readPerss,以便它直接执行操作,将(String, Int) 结果存储在列表中,而不是累积IO 动作

readPerss :: (Ord t, Num t) => t -> IO [(String, Int)]
-- Change [IO …] to IO […]:         ~~~~~~~~~~~~~~~~~~

readPerss n
  | n > 0 = do
    pers <- readPers
    perss <- readPerss (n - 1)
    return (pers : perss)
  | otherwise = return []

我知道,如果这是一项家庭作业或练习,则可能不应该使用库函数,但是在典型代码中,“重复xn次并累积结果”通常用replicateM n x

replicateM :: Applicative m => Int -> m a -> m [a]

答案 1 :(得分:2)

这就是我一直这样做的方式(不是来自代码挑战)。我总是尽快将IO和逻辑分开。完美的作品(除非N非常大)。

import Data.List.Split (chunksOf)

type Person = (String, Int)

main = do
    x <- getContents
    putStrLn $ program x

program :: String -> String
program s = “Oldest is “ ++ x ++ “ (“ ++ (show y) ++ “ years old).”
    where
    (x, y)  = solve persons
    persons = [(name, read age :: Int) | [name, age] <- chunksOf 2 . tail . lines $ s]

solve :: [Person] -> Person
solve ls = undefined 

我将undefined留给您。