haskell - 为什么我不能在这里放一个打印函数语句?

标签 haskell boolean monads io-monad do-notation

我正在尝试使用 try-catch block 跟踪代码:

import System.Environment  
import System.IO  
import System.IO.Error  
import Control.Exception

isBinary :: String -> Bool
isBinary ss = do 
    print "In isBinary fn"   -- works if this line is removed.
    let ans = any (\c -> ord c > 127) ss
    ans

toTry :: String -> IO ()  
toTry firline = do
        print "In toTry fn."
        let answer = isBinary firline
        if not answer then do
            print "Sent line not binary: "
        else
            print "Sent line binary"

handler :: IOError -> IO ()  
handler e = putStrLn "Whoops, had some trouble!"  

ss = "this is a test"
main = do 
    toTry ss `catch` handler

但是,我收到以下错误:

$ runghc trycatch3.hs 

trycatch3.hs:9:9: error:
    • Couldn't match expected type ‘Bool’ with actual type ‘IO Bool’
    • In a stmt of a 'do' block: print "in isBinary fn"
      In the expression:
        do { print "in isBinary fn";
             let ans = any (\ c -> ...) ss;
             return ans }
      In an equation for ‘isBinary’:
          isBinary ss
            = do { print "in isBinary fn";
                   let ans = ...;
                   return ans }

trycatch3.hs:10:30: error:
    • Variable not in scope: ord :: Char -> Integer
    • Perhaps you meant one of these:
        ‘or’ (imported from Prelude), ‘odd’ (imported from Prelude)

如果从 isBinary 函数中删除 print 语句,错误就会消失,程序运行良好。

为什么我不能在这个函数中放入打印语句?

最佳答案

答案是,“因为类型”。具体来说:

isBinary :: String -> Bool
isBinary ss = do 
  ....

因为它是 do block ,isBinary 的返回类型必须 匹配单子(monad)类型 Monad m => m t对于一些 m还有一些t .在这里,因为 print "" :: IO () , mIO , 所以应该是

isBinary :: String -> IO Bool
isBinary ss = do 

现在

    print "In isBinary fn"                 -- works
    let ans = any (\c -> ord c > 127) ss   -- also works
    ans                                    -- doesn't work

ans再次因为类型而不起作用。它的类型是 Bool , 但它必须是 IO Bool -- 首先,因为这个 do block 属于 IO monad,由于 print ;其次,因为整个函数的返回类型。

相反,使用

    return ans

现在它可以工作了,因为return向 monadic 上下文中注入(inject)一个值,并且是最后一个 do block 值,它成为 do 产生的值整体 block (如果 return val 出现在中间,它只是将 val 传递到组合计算的下一步)。

函数toTry必须扩充才能使用新定义:

toTry :: String -> IO ()  
toTry firline = do
        print "In toTry fn."
        -- let answer = isBinary firline    -- incorrect, now!
        answer <- isBinary firline          -- isBinary ... :: IO Bool
        if not answer then do               --       answer ::    Bool
            print "Sent line not binary: "
        else
            print "Sent line binary"

m a<- 的右侧, a在左边。

参见 this有关 do 的一般说明符号。

关于haskell - 为什么我不能在这里放一个打印函数语句?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56220932/

相关文章:

haskell - 使用正则表达式和模式匹配过滤 [[String]]

Javascript/Ember - 切换变量的 boolean 值

ios - 如何使用枚举而不是三种不同的状态?

c++ - 我正在尝试从类中的 boolean 值返回一个字符串,该字符串一直返回 true

haskell - Haskell 中的 Monad 和 Purity

haskell - 结合 StateT 和 State monad

Haskell 奇怪的种类 : Kind of (->) is ? ? ->? -> *

haskell - 为什么 Haskell 不能优化这个重复的函数调用?

haskell - 如何在纯脚本中构建应用程序

haskell - do-notation 是特定于 "base:GHC.Base.Monad"的吗?