`print <$>(print“ hello”)`が“ hello”を出力するのはなぜですか?


14

を計算するときIO (IO ())(IO ())およびの両方()が計算されるので、なぜ

main :: IO (IO ())
main = print <$> (print "Hello, World!")

印刷する

"Hello, World!"

ない

IO "Hello, World!" -- ??
"Hello, World!"

3
基本的にfmap print (print "Hello World")は、最初のパラメータであるprint関数をの結果に適用しprint "Hello World"ます。これは単に、アクションが実行されたprint ()後に呼び出すことと同じですprint "Hello World"
Reduの

@Redu正しいですが、の呼び出しprint ()は評価されず、そのアクションは実行されません(()標準出力に出力されます)。したがって、「print ()...の後の呼び出し」は少し誤解を招く可能性があります(IMO)。
カイ

回答:


21
main :: IO (IO ())
main = print <$> (print "Hello, World!")

モナドの法則のおかげで、

main :: IO (IO ())
main = do 
   result <- print "Hello, World!"
   return (print result)

現在、print常に()結果として返されるため、コード全体は次と同等です。

main :: IO (IO ())
main = do 
   _ <- print "Hello, World!"
   return (print ())

最後に、の結果mainは単に破棄されます。つまり、最後の行return (putStrLn "this is ignored")は同じ効果を持つ可能性があり、同じ効果があります。

したがって、コードは最初のものだけを実行しprint "Hello, World!"ます。

常に定義することをお勧めしますmain :: IO ()。Haskellではを宣言できますmain :: IO AnyTypeHereが、これは(IMO)で混乱します。

文字列全体を引用してエスケープするため、文字列を出力するのputStrLnではなく、を使用することもお勧めしますprint


5
f <$> a ≡ a >>= \r -> return $ f rこれはこの状況に特定のことだけではなく、実際にはどのモナドにも当てはまります。
leftaroundabout
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.