【发布时间】:2019-02-27 18:04:52
【问题描述】:
我最近需要将head 放在两个一元操作之间。这是 SSCCE:
module Main where
f :: IO [Int]
f = return [1..5]
g :: Int -> IO ()
g = print
main = do
putStrLn "g <$> head <$> f"
g <$> head <$> f
putStrLn "g . head <$> f"
g . head <$> f
putStrLn "head <$> f >>= g"
head <$> f >>= g
这个程序格式正确,编译时没有警告。但是,上述 3 个版本中只有一个版本有效1。这是为什么呢?
具体来说,将f 和g 与head 在中间链接的最佳方式是什么?我最终使用了第三个(以do 表示法的形式),但我不太喜欢它,因为它应该是一个微不足道的单行2。
1 剧透警告:第三个是唯一一个打印1的;另外两个都在runhaskell和repl下保持沉默。
2 我确实意识到这些都是单行的,但是在唯一可行的情况下,操作顺序确实令人困惑。
【问题讨论】:
-
(<$>)是左关联的,这意味着g <$> head <$> f是(g <$> head) <$> f。 -
@WillemVanOnsem 当然可以,但
g <$> (head <$> f)也不起作用。坦率地说,我有点困惑为什么上面的 any 不起作用。 -
在上面你
fmap的值,所以g <$> head <$> f基本上创建一个IO (IO [Int])),而不是IO ()。 -
啊,我读到这里笑了。如此明显,却又如此棘手!把它放在一个答案中,这样我就可以接受了:)我真的想知道是否有可能至少为此发出警告;毕竟这是一个无意丢弃的值。
-
@BartekBanachewicz 如果您希望此类错误出现错误,您可以将其编写为绑定:
() <- g . head <$> f。这会产生类型错误。
标签: haskell monads applicative