1

想象一下,我通过标准输入读取了一个如下所示的输入块:

3
12
16
19

第一个数字是后面的行数。我必须通过一个函数处理这些数字并报告结果,并用空格分隔。

所以我写了这个主函数:

main = do         
    num <- readLn
    putStrLn $ intercalate " " [ show $ myFunc $ read getLine | c <- [1..num]]

当然,由于read getLine.

但是正确(阅读:Haskell方式)正确执行此操作的方法是什么?甚至可以将此函数编写为单行吗?

4

3 回答 3

3

甚至可以将此函数编写为单行吗?

嗯,确实如此,而且有点简洁,但请自己看:

main = interact $ unwords . map (show . myFunc . read) . drop 1 . lines

那么,这是如何工作的呢?

  1. interact :: (String -> String) -> IO ()从 STDIN 获取所有内容,将其传递给给定的函数,然后打印输出。
  2. 我们使用unwords . map (show . myFunc . read) . drop 1 . lines :: String -> String
    1. lines :: String -> [String]在行尾断开字符串。
    2. drop 1删除第一行,因为我们实际上并不需要行数。
    3. map (show . myFunc . read)将每个转换String为正确的类型,使用myFunc,然后将其转换回 `String.
    4. unwords基本相同intercalate " "

但是,请记住,这interact对 GHCi 不太友好。

于 2015-08-18T12:13:06.770 回答
2

<$>您可以使用(或fmap)构建一元操作列表,并使用sequence.

λ intercalate " " <$> sequence [show . (2*) . read <$> getLine | _ <- [1..4]]
1
2
3
4
"2 4 6 8"
于 2015-08-18T11:10:48.477 回答
2

甚至可以将此函数编写为单行吗?

当然可以,但是函数的最后一行有问题main。因为你想intercalate " "申请

[ show $ myFunc $ read getLine | c <- [1..num]]

我猜你希望后者有 type [String],但它实际上不是一个类型良好的表达式。这怎么能解决?我们先定义

getOneInt :: IO Int
getOneInt = read <$> getLine

为方便起见(我们将在代码中多次使用它)。现在,你的意思可能是这样的

[ show . myFunc <$> getOneInt | c <- [1..num]]

其中,如果 的 类型myFunc与其余的一致,则具有 type [IO String]。然后,您可以将其传递给以sequence获取类型的值IO [String]。最后,您可以“传递”(使用=<<)到

putStrLn . intercalate " "

为了获得所需的单线:

import Control.Monad ( replicateM )
import Data.List     ( intercalate )

main :: IO ()
main = do
    num  <- getOneInt
    putStrLn . intercalate " " =<< sequence [ show . myFunc <$> getOneInt | c <- [1..num]]
  where
    myFunc = (* 3) -- for example

getOneInt :: IO Int
getOneInt = read <$> getLine

在 GHCi 中:

λ> main
3
45
23
1
135 69 3

但是,代码是否惯用且可读?没那么多,在我看来...

[...]正确(阅读:Haskell方式)正确执行此操作的方法是什么?

没有“正确”的做法,但以下内容对我来说更自然和可读:

import Control.Monad ( replicateM )
import Data.List     ( intercalate )

main :: IO ()
main = do
    n  <- getOneInt
    ns <- replicateM n getOneInt
    putStrLn $ intercalate " " $ map (show . myFunc) ns
  where
    myFunc = (* 3) -- replace by your own function

getOneInt :: IO Int
getOneInt = read <$> getLine

或者,如果您想避开do符号:

main =
    getOneInt                                        >>=
    flip replicateM getOneInt                        >>=
    putStrLn . intercalate " " . map (show . myFunc)
  where
    myFunc = (* 3) -- replace by your own function
于 2015-08-18T11:12:39.987 回答