在线阅读数字
Reading numbers inline
假设我通过 stdin 读取了一个如下所示的输入块:
3
12
16
19
第一个数字是后面的行数。我必须通过函数处理这些数字并报告由 space.
分隔的结果
所以我写了这个主要功能:
main = do
num <- readLn
putStrLn $ intercalate " " [ show $ myFunc $ read getLine | c <- [1..num]]
当然,由于 read getLine
.
,该函数无法编译
但是正确的(阅读:Haskell 方式)正确执行此操作的方法是什么?甚至可以将这个函数写成一行吗?
您可以使用 <$>
(or fmap
) and execute them all with sequence
构建单子操作列表。
λ intercalate " " <$> sequence [show . (2*) . read <$> getLine | _ <- [1..4]]
1
2
3
4
"2 4 6 8"
Is it even possible to write this function as a one-liner?
当然可以,但是您的 main
函数的最后一行有问题。因为您正在尝试将 intercalate " "
应用于
[ show $ myFunc $ read getLine | c <- [1..num]]
我猜您希望后者具有 [String]
类型,但实际上它不是类型正确的表达式。这怎么能解决?我们先定义
getOneInt :: IO Int
getOneInt = read <$> getLine
为了方便起见(我们将在代码中多次使用它)。现在,你的意思可能是
[ show . myFunc <$> getOneInt | c <- [1..num]]
如果 myFunc
的类型与其余类型一致,则类型为 [IO String]
。然后,您可以将其传递给 sequence
以获得 IO [String]
类型的值。最后,你可以 "pass" 那(使用 =<<
)到
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
不过,代码是否惯用且可读?没那么多,在我看来...
[...] what is the correct (read: the Haskell way) way to do this properly?
没有 "correct" 的方法,但我觉得以下内容更自然、更易读:
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
Is it even possible to write this function as a one-liner?
嗯,是的,而且有点简洁,但是你自己看:
main = interact $ unwords . map (show . myFunc . read) . drop 1 . lines
那么,这是如何工作的?
interact :: (String -> String) -> IO ()
从 STDIN 获取所有内容,将其传递给给定的函数,并打印输出。
- 我们使用
unwords . map (show . myFunc . read) . drop 1 . lines :: String -> String
:
lines :: String -> [String]
在行尾断开字符串。
drop 1
删除第一行,因为我们实际上不需要行数。
map (show . myFunc . read)
将每个 String
转换为正确的类型,使用 myFunc
,然后将其转换回 `String.
unwords
与intercalate " "
基本相同。
但是,请记住 interact
对 GHCi 不是很友好。
假设我通过 stdin 读取了一个如下所示的输入块:
3
12
16
19
第一个数字是后面的行数。我必须通过函数处理这些数字并报告由 space.
分隔的结果所以我写了这个主要功能:
main = do
num <- readLn
putStrLn $ intercalate " " [ show $ myFunc $ read getLine | c <- [1..num]]
当然,由于 read getLine
.
但是正确的(阅读:Haskell 方式)正确执行此操作的方法是什么?甚至可以将这个函数写成一行吗?
您可以使用 <$>
(or fmap
) and execute them all with sequence
构建单子操作列表。
λ intercalate " " <$> sequence [show . (2*) . read <$> getLine | _ <- [1..4]]
1
2
3
4
"2 4 6 8"
Is it even possible to write this function as a one-liner?
当然可以,但是您的 main
函数的最后一行有问题。因为您正在尝试将 intercalate " "
应用于
[ show $ myFunc $ read getLine | c <- [1..num]]
我猜您希望后者具有 [String]
类型,但实际上它不是类型正确的表达式。这怎么能解决?我们先定义
getOneInt :: IO Int
getOneInt = read <$> getLine
为了方便起见(我们将在代码中多次使用它)。现在,你的意思可能是
[ show . myFunc <$> getOneInt | c <- [1..num]]
如果 myFunc
的类型与其余类型一致,则类型为 [IO String]
。然后,您可以将其传递给 sequence
以获得 IO [String]
类型的值。最后,你可以 "pass" 那(使用 =<<
)到
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
不过,代码是否惯用且可读?没那么多,在我看来...
[...] what is the correct (read: the Haskell way) way to do this properly?
没有 "correct" 的方法,但我觉得以下内容更自然、更易读:
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
Is it even possible to write this function as a one-liner?
嗯,是的,而且有点简洁,但是你自己看:
main = interact $ unwords . map (show . myFunc . read) . drop 1 . lines
那么,这是如何工作的?
interact :: (String -> String) -> IO ()
从 STDIN 获取所有内容,将其传递给给定的函数,并打印输出。- 我们使用
unwords . map (show . myFunc . read) . drop 1 . lines :: String -> String
:lines :: String -> [String]
在行尾断开字符串。drop 1
删除第一行,因为我们实际上不需要行数。map (show . myFunc . read)
将每个String
转换为正确的类型,使用myFunc
,然后将其转换回 `String.unwords
与intercalate " "
基本相同。
但是,请记住 interact
对 GHCi 不是很友好。