fmap 到 do 块失败并出现打印错误
fmap into a do block fails with a print error
我试图理解为什么我用 do-block 编写的函数不能重写以在列表上 fmap 一个类似的 lambda 表达式。
我有以下内容:
-- This works
test1 x = do
let m = T.pack $ show x
T.putStrLn m
test1 1
生产
1
但是
-- This fails
fmap (\x -> do
let m = T.pack $ show x
T.putStrLn m
) [1..10]
-- And this also fails
fmap (\x -> do
T.putStrLn $ T.pack $ show x
) [1..10]
错误:
<interactive>:1:1: error:
• No instance for (Show (IO ())) arising from a use of ‘print’
• In a stmt of an interactive GHCi command: print it
我的 putStrLn 在工作和非工作之间是一致的。进口是一样的。我打印的 show-pack-putstrln 舞蹈在工作和非工作之间也是一致的。
打印的使用在工作和非工作之间发生变化是怎么回事?
更新 1
-- I was also surprised that this fails
fmap (T.putStrLn $ T.pack $ show) [1..10]
-- it seemed as similar as possible to the test1 function but mapped.
<interactive>:1:7: error:
• Couldn't match expected type ‘Integer -> b’ with actual type ‘IO ()’
• In the first argument of ‘fmap’, namely ‘(T.putStrLn $ pack $ show)’
In the expression: fmap (T.putStrLn $ pack $ show) [1 .. 10]
In an equation for ‘it’: it = fmap (T.putStrLn $ pack $ show) [1 .. 10]
• Relevant bindings include it :: [b] (bound at <interactive>:1:1)
<interactive>:1:29: error:
• Couldn't match type ‘() -> String’ with ‘String’
Expected type: String
Actual type: () -> String
• Probable cause: ‘show’ is applied to too few arguments
In the second argument of ‘($)’, namely ‘show’
In the second argument of ‘($)’, namely ‘pack $ show’
In the first argument of ‘fmap’, namely ‘(T.putStrLn $ pack $ show)’
更新 2
-- This lambda returns x of the same type as \x
-- even while incidentally printing along the way
fmap (\x -> do
let m = T.pack $ show x
T.putStrLn $ m
return x
) [1..10]
但也失败了:
<interactive>:1:1: error:
• No instance for (Show (IO Integer)) arising from a use of ‘print’
• In a stmt of an interactive GHCi command: print it
fmap f [1..10]
的类型是 [T]
,其中 T
是 f
的 return 类型。
在你的例子中,T = IO ()
,所以完整表达式的类型是 [IO ()]
。
无法打印 IO 操作,因此当您尝试打印该列表时 GHCi 会报错。您可能想要 运行 这些操作而不是打印它们,使用类似 sequence_ (fmap f [1..10])
.
或者,考虑放弃 fmap
并使用
之类的东西
import Data.Foldable (for_)
main = do
putStrLn "hello"
for_ [1..10] $ \i -> do
putStrLn "in the loop"
print (i*2)
putStrLn "out of the loop"
您写道:
but when I change the return type of the lambda to be the same as the x that comes in as \x as I do in the update 2 ...
不,不。你不知道。 lambda 函数 return 是其 最后一个表达式 的值。您的 lambda 函数中只有 一个 表达式——整个 do { ... }
块 定义了一个值,即 lambda 函数的 return 值。不是 x
。 return
属于 do
,不是 lambda 表达式。如果我们用明确的分隔符来写它更容易看出,如
fmap (\x -> do {
let m = T.pack $ show x ;
T.putStrLn $ m ;
return x
} ) [1..10]
do
块作为一个整体与其每行语句具有相同的 monadic 类型。
其中之一是 putStrLn ...
,其类型是 IO ()
。所以你的 lambda 函数 returns IO t
对于某些 t
。
并且由于 return x
,t
是 x
的类型。我们有 return :: Monad m => t -> m t
,所以 m ~ IO
是 return :: t -> IO t
。
x
来自参数列表 Num t => [t]
,所以总的来说你有
Num t => fmap (fx :: t -> IO t) (xs :: [t]) :: [IO t]
或
xs :: [t]
fx :: t -> IO t
----------------------------
fmap fx xs :: [IO t]
我试图理解为什么我用 do-block 编写的函数不能重写以在列表上 fmap 一个类似的 lambda 表达式。
我有以下内容:
-- This works
test1 x = do
let m = T.pack $ show x
T.putStrLn m
test1 1
生产
1
但是
-- This fails
fmap (\x -> do
let m = T.pack $ show x
T.putStrLn m
) [1..10]
-- And this also fails
fmap (\x -> do
T.putStrLn $ T.pack $ show x
) [1..10]
错误:
<interactive>:1:1: error:
• No instance for (Show (IO ())) arising from a use of ‘print’
• In a stmt of an interactive GHCi command: print it
我的 putStrLn 在工作和非工作之间是一致的。进口是一样的。我打印的 show-pack-putstrln 舞蹈在工作和非工作之间也是一致的。
打印的使用在工作和非工作之间发生变化是怎么回事?
更新 1
-- I was also surprised that this fails
fmap (T.putStrLn $ T.pack $ show) [1..10]
-- it seemed as similar as possible to the test1 function but mapped.
<interactive>:1:7: error:
• Couldn't match expected type ‘Integer -> b’ with actual type ‘IO ()’
• In the first argument of ‘fmap’, namely ‘(T.putStrLn $ pack $ show)’
In the expression: fmap (T.putStrLn $ pack $ show) [1 .. 10]
In an equation for ‘it’: it = fmap (T.putStrLn $ pack $ show) [1 .. 10]
• Relevant bindings include it :: [b] (bound at <interactive>:1:1)
<interactive>:1:29: error:
• Couldn't match type ‘() -> String’ with ‘String’
Expected type: String
Actual type: () -> String
• Probable cause: ‘show’ is applied to too few arguments
In the second argument of ‘($)’, namely ‘show’
In the second argument of ‘($)’, namely ‘pack $ show’
In the first argument of ‘fmap’, namely ‘(T.putStrLn $ pack $ show)’
更新 2
-- This lambda returns x of the same type as \x
-- even while incidentally printing along the way
fmap (\x -> do
let m = T.pack $ show x
T.putStrLn $ m
return x
) [1..10]
但也失败了:
<interactive>:1:1: error:
• No instance for (Show (IO Integer)) arising from a use of ‘print’
• In a stmt of an interactive GHCi command: print it
fmap f [1..10]
的类型是 [T]
,其中 T
是 f
的 return 类型。
在你的例子中,T = IO ()
,所以完整表达式的类型是 [IO ()]
。
无法打印 IO 操作,因此当您尝试打印该列表时 GHCi 会报错。您可能想要 运行 这些操作而不是打印它们,使用类似 sequence_ (fmap f [1..10])
.
或者,考虑放弃 fmap
并使用
import Data.Foldable (for_)
main = do
putStrLn "hello"
for_ [1..10] $ \i -> do
putStrLn "in the loop"
print (i*2)
putStrLn "out of the loop"
您写道:
but when I change the return type of the lambda to be the same as the x that comes in as \x as I do in the update 2 ...
不,不。你不知道。 lambda 函数 return 是其 最后一个表达式 的值。您的 lambda 函数中只有 一个 表达式——整个 do { ... }
块 定义了一个值,即 lambda 函数的 return 值。不是 x
。 return
属于 do
,不是 lambda 表达式。如果我们用明确的分隔符来写它更容易看出,如
fmap (\x -> do {
let m = T.pack $ show x ;
T.putStrLn $ m ;
return x
} ) [1..10]
do
块作为一个整体与其每行语句具有相同的 monadic 类型。
其中之一是 putStrLn ...
,其类型是 IO ()
。所以你的 lambda 函数 returns IO t
对于某些 t
。
并且由于 return x
,t
是 x
的类型。我们有 return :: Monad m => t -> m t
,所以 m ~ IO
是 return :: t -> IO t
。
x
来自参数列表 Num t => [t]
,所以总的来说你有
Num t => fmap (fx :: t -> IO t) (xs :: [t]) :: [IO t]
或
xs :: [t]
fx :: t -> IO t
----------------------------
fmap fx xs :: [IO t]