简体   繁体   English

为什么我不能使用(cnt < - hGetContents h)表达式而不是cnt?

[英]Why I can't use the (cnt <- hGetContents h) expression instead of cnt?

I learn Haskell. 我学习Haskell。 It works fine: 它工作正常:

import System.IO

main = do
  h <- openFile "text.txt" ReadMode
  cnt <- hGetContents h
  mapM_ putStrLn $ lines cnt
  hClose h

But this isn't working: 但这不起作用:

import System.IO

main = do
  h <- openFile "text.txt" ReadMode  
  mapM_ putStrLn $ lines (cnt <- hGetContents h)
  hClose h

Why my second variant isn't working? 为什么我的第二个变种不起作用? I expected both variants are equal, because the (cnt <- hGetContents h) is an expression and returns the value too. 我预计两个变体都是相同的,因为(cnt <- hGetContents h)是一个表达式并返回该值。

The problem is that cnt <- hGetContents h is not an expression, it's some special syntax sugar inside do notation . 问题是cnt <- hGetContents h 不是表达式,它是一些特殊的语法糖里面的表示法 This means it is a different way of writing the following normal Haskell code: 这意味着它是编写以下普通Haskell代码的不同方式:

hGetContents h >>= \ cnt -> {- rest of do block -}

The part before the {- rest of the do block -} is not a whole expression here, because the rest of the do block is needed to complete the lambda's body. {- rest of the do block -}之前的部分在这里不是一个完整的表达式,因为需要其余的do块来完成lambda的主体。

You could desugar it manually to get something like: 您可以手动去除它以获得类似的东西:

hGetContents h >>= \ cnt -> mapM_ putStrLn (lines cnt)

or the point-free version 或无点版本

hGetContents h >>= mapM_ putStrLn . lines

You can tell that it's a special expression because it introduces a new identifier ( cnt ) that you can use in the rest of your code, outside of the expression itself. 您可以告诉它它是一个特殊的表达式,因为它引入了一个新的标识符( cnt ),您可以在表达式本身之外的其余代码中使用它。 This is not something that normal Haskell expressions get to do (at least without compile-time magic). 这不是普通的Haskell表达式所做的事情(至少没有编译时魔术)。

cnt <- hGetContents h is essentially syntactical sugar for hGetContents h >>= \\cnt -> . cnt <- hGetContents h基本上是hGetContents h >>= \\cnt ->语法糖。

It is not an expression, it is sugar intended for its own line in a do-block. 不是一个表达式,它是在一个块中用于自己的行的糖。

If you still want to keep it on one line, you can do this, though you will not be able to refer to the file's contents later on: 如果您仍希望将其保留在一行,则可以执行此操作,但稍后您将无法参考该文件的内容:

import System.IO

main = do
  h <- openFile "text.txt" ReadMode  
  hGetContents h >>= mapM_ putStrLn . lines
  hClose h

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM