在无意义编程时,readFile和IO monad之间没有合作

Van*_*uel 4 io monads haskell pointfree

为什么countInFile1和countInFile3有编译器错误,当countInFile0和countInFile2没有时.这四个都是一回事.

count :: String -> String -> Int
count w = length . filter (==w) . words

present :: String -> String -> IO String
present w = return . show . count w

-- VALID: pointed readFile, regular present
countInFile0 :: String -> FilePath -> IO ()
countInFile0 w f = putStrLn =<< present w =<< readFile f

-- INVALID: pointless readFile, regular present
countInFile1 :: String -> FilePath -> IO ()
countInFile1 w = putStrLn =<< present w =<< readFile

-- VALID: pointed readFile, inline present
countInFile2 :: String -> FilePath -> IO ()
countInFile2 w f = putStrLn =<< (return . show . count w) =<< readFile f

-- INVALID: pointless readFile, inline present
countInFile3 :: String -> FilePath -> IO ()
countInFile3 w = putStrLn =<< (return . show . count w) =<< readFile

main = do
  countInFile0 "bulldogs" "bulldogs.txt"
  countInFile1 "bulldogs" "bulldogs.txt"
  countInFile2 "bulldogs" "bulldogs.txt"
  countInFile3 "bulldogs" "bulldogs.txt"
Run Code Online (Sandbox Code Playgroud)

另外,为什么countInFile3有这个额外的错误,countInFile1没有:

example_one.hs:21:27:
    No instance for (Monad ((->) FilePath))
      arising from a use of `=<<'
    Possible fix:
      add an instance declaration for (Monad ((->) FilePath))
    In the expression:
        putStrLn =<< (return . show . count w) =<< readFile
    In an equation for `countInFile3':
        countInFile3 w
          = putStrLn =<< (return . show . count w) =<< readFile
Run Code Online (Sandbox Code Playgroud)

app*_*ive 9

countInFile1countInFile3,因为你正在撰写形式的三件事情a -> IO b,你在想所谓Kleisli组成的,在<=<Control.Monad.尝试

 countInFile1 w = putStrLn <=< present w <=< readFile
 countInFile3 w = putStrLn <=< return . show . count w <=< readFile
Run Code Online (Sandbox Code Playgroud)

或者你可以countInFile3 w file = ... =<< readFile file像其他地方一样写作.readFile file(带参数)是一个IO String,因此可以通过>>=或传递=<<给任何一个String -> IO b.但这并不像你想要的那样猛烈. readFile只是它本身就是一个FilePath -> IO String所以它可以>=>与任何人String -> IO b一起制作一个FilePath -> IO b等等b -> IO c,在你的情况下以一个结尾FilePath -> IO ()

第二个错误来自ghc尝试读取=<< readFile,为此需要readFilemb为某些monad m,所以它安定下来Monad ((->) FilePath)(这实际上有意义Control.Monad.Instances,但只会延迟得到第一个错误.)

如果你将file参数添加到这些参数,那么,

 countInFile1 w file = (putStrLn <=< present w <=< readFile) file 
Run Code Online (Sandbox Code Playgroud)

它是可能是因为您解析countInFile2countInFile0这种方式,而诠释=<<<=<时候实际上他们是像这样:

 countInFile0 w file = putStrLn =<< present w =<< (readFile file)
Run Code Online (Sandbox Code Playgroud)

差异与之间的差异相同

 f n = (even . (+1) . (*3)) n
Run Code Online (Sandbox Code Playgroud)

或者等价的

 f   = even . (+1) . (3*)
Run Code Online (Sandbox Code Playgroud)

而另一方面

 f n = even $ (+1) $ 3 * n  -- cp. your 0 and 2
Run Code Online (Sandbox Code Playgroud)

如果你n从这里删除双方

 f   = even $ (+1) $ (3*)  -- cp. your 1 and 3
Run Code Online (Sandbox Code Playgroud)

你会得到类似于你所看到的类型错误:

 No instance for (Integral (a0 -> a0)) arising from a use of `even'
Run Code Online (Sandbox Code Playgroud)

在您使用的地方,$您需要参数n- 如您使用的位置>>==<<您需要参数file.随着.,如<=<,你不知道.

  • +1:清楚,很好地解释,演示了可爱的`<= <`这是我们都想要的,真的,内心深处. (2认同)

Sat*_*vik 8

函数应用程序的优先级高于中缀=<<运算符.

所以f =<< g a相当于f =<< (g a)和不相同(f =<< g) a.