Chr*_*ski 6 haskell lazy-evaluation applicative io-monad
abc :: IO (Int)
abc = do
print "abc"
pure $ 10
xyz :: IO (Int)
xyz = undefined
main :: IO ()
main = do
x <- (((+) <$> abc <*> abc) <* xyz)
print x
Run Code Online (Sandbox Code Playgroud)
Why in the above is xyz being evaluated? I would assume due to Haskell's lazy nature it would not need to evaluate xyz (and hence not reach the undefined)?
My assumption is based on the type of <*:
Prelude> :t (<*)
(<*) :: Applicative f => f a -> f b -> f a
Run Code Online (Sandbox Code Playgroud)
Following on with:
-- | Sequence actions, discarding the value of the first argument.
(*>) :: f a -> f b -> f b
a1 *> a2 = (id <$ a1) <*> a2
Run Code Online (Sandbox Code Playgroud)
And:
(<$) :: a -> f b -> f a
(<$) = fmap . const
Run Code Online (Sandbox Code Playgroud)
And hence f b never gets used.
Is there a way I can understand / investigate why this is being evaluated strictly? Would looking at the GHC compiled Core be helpful in this?
Thanks to the discussion in the comments it seems (please someone correct me if I'm wrong) it's due to the Monad implementation of the IO because the following two statements seem to evaluate differently:
Identity:
runIdentity $ const <$> (pure 1 :: Identity Int) <*> undefined
1
Run Code Online (Sandbox Code Playgroud)
IO:
const <$> (pure 1 :: IO Int) <*> undefined
*** Exception: Prelude.undefined
Run Code Online (Sandbox Code Playgroud)
(<*)不使用b中的值f b,但它确实使用f效果,因此它必须检查第二个参数。
为什么 [
putStrLn "Hello!" *> putStrLn "World!"] 两者都执行,const (print "test") (print "test2")而不执行?
在类型const...
const :: a -> b -> a
Run Code Online (Sandbox Code Playgroud)
...a和b都是完全参数化的,没有其他需要处理的。但对于(<*),情况就大不相同了。对于初学者来说,(<*)是 的一种方法Applicative,因此任何为其编写实例Applicative的IO人都可以提供具体的...
(<*) :: IO a -> IO b -> IO a
Run Code Online (Sandbox Code Playgroud)
...使用IO特定函数以任何认为必要的方式组合两个参数的效果的实现。
此外,即使(<*)不是 的方法Applicative,它的类型......
(<*) :: Applicative f => f a -> f b -> f a
Run Code Online (Sandbox Code Playgroud)
...虽然 和a是b完全参数化的,f但由于Applicative约束,不是完全参数化的。它的实现可以使用 的其他方法Applicative,这些方法可以并且在大多数情况下将会使用两个参数的效果。
请注意,这不是IO特定问题。例如,这里(<*) @Maybe并没有忽略第二个参数的影响:
GHCi> Just 1 <* Just 2
Just 1
GHCi> Just 1 <* Nothing
Nothing
Run Code Online (Sandbox Code Playgroud)