You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Haskell:如何在do块中内联[a]->IO a类型的辅助函数?

问题与解答:将[a]->IO a函数内联到Haskell do块中

问题描述

我正在学习Graham Hutton所著的《Programming in Haskell》(第二版),刚完成了第138页的练习10.5。该练习要求编写一个类型为adder :: IO ()的函数,它能交互式读取n个数字,求和后输出结果,示例运行效果如下:

> adder
How many numbers? 3
5
4
6
The total is 15

已知readInt和readLine函数定义如下:

readInt :: IO Int
readInt = do
  line <- readLine
  return (read line :: Int)

readLine :: IO String
readLine = do
  c <- getChar
  case c of
    '\n' -> return []
    _ -> do
      cs <- readLine
      return (c:cs)

我已实现了adder函数:

adder :: IO ()
adder = do
  putStr "How many numbers? "
  n <- readInt
  ns <- sequence [readInt | _ <- [1..n]]
  sum <- sumUp ns
  putStr $ "The total is " ++ (show sum) ++ "\n"

sumUp :: [Int] -> IO Int
sumUp xs = return $ foldl (+) 0 xs

我对当前方案基本满意,但希望将sumUp函数内联到do块中,却不知如何操作,请问该如何将[a]->IO a类型的函数内联到do块中?

解答

你的sumUp函数本质是把纯函数计算结果包装进IO上下文里——foldl (+) 0 xs是纯的数值求和操作,只是用return把它提升到IO类型。要内联它,有几种简洁且符合Haskell风格的方式:

方式1:用let绑定纯计算结果(推荐)

在do块中,let可以直接绑定纯值(不需要IO上下文),之后直接使用这个值即可,无需额外的return或<-:

adder :: IO ()
adder = do
  putStr "How many numbers? "
  n <- readInt
  ns <- sequence [readInt | _ <- [1..n]]
  let total = foldl (+) 0 ns  -- 绑定纯求和结果
  putStr $ "The total is " ++ show total ++ "\n"

方式2:直接内嵌计算表达式

如果追求代码紧凑,可以把求和逻辑直接写在输出语句里,甚至用Haskell内置的sum函数替代手动的foldl,让代码更简洁:

adder :: IO ()
adder = do
  putStr "How many numbers? "
  n <- readInt
  ns <- sequence [readInt | _ <- [1..n]]
  putStr $ "The total is " ++ show (sum ns) ++ "\n"

核心逻辑说明

原来的sum <- sumUp ns是从IO Int上下文里取出内部的Int值,但sumUp本身只是对纯求和结果做了一层IO包装。既然求和是纯操作,我们完全可以直接计算纯值,避免不必要的IO上下文包装,这也是Haskell中区分纯代码与IO代码的最佳实践。

内容的提问来源于stack exchange,提问作者Patrick Bucher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 07:55:23