我正在尝试学习Haskell,并希望编写一个小程序,将文件内容打印到屏幕上.当我将其加载到GHCi时,我收到以下错误:
'do'结构中的最后一个语句必须是表达式
我知道这个问题已经在这里被提出了:Haskell - "'do'结构中的最后一个语句必须是一个表达式".
即使我的代码非常相似,我仍然无法弄清楚问题.如果有人能指出我的问题,我会非常感激.
module Main (main) where
import System.IO
import System(getArgs)
main :: IO()
main = do
args <- getArgs
inh <- openFile $ ReadMode head args
printFile inh
hClose inh
printFile :: Handle -> IO ()
printFile handle = do
end <- hIsEOF handle
if end
then return ()
else do line <- hGetLine handle
putStrLn line
printFile handle
Run Code Online (Sandbox Code Playgroud) 我是haskell的新手,我正在尝试理解本文档中用于创建Monadic解析器的方法https://www.cs.nott.ac.uk/~gmh/pearl.pdf
我没有完全遵循它,而是试图以不同的方式做到这一点,以便正确理解它,因此,我最终得到了这段代码
newtype Parser a = Parser (String -> Maybe (a, String))
item :: Parser Char
item = Parser (\cs -> case cs of
"" -> Nothing
(c:cs) -> Just (c, cs))
getParser (Parser x) = x
instance Monad Parser where
return x = Parser (\cs -> Just (x,cs))
(Parser p) >>= f = Parser (\cs -> let result = p cs in
case result of
Nothing -> Nothing
Just (c,cs') -> getParser (f c) cs')
takeThreeDropSecond :: Parser …Run Code Online (Sandbox Code Playgroud) 虽然我可以应用一个函数两次并将结果绑定到元组:
let foo :: Num a => a -> a
foo x = x + 1
let (x,y) = (foo 10, foo 20)
Run Code Online (Sandbox Code Playgroud)
这不能在一个do块内完成(至少我不知道如何正确地做到这一点):
let bar :: Num a => a -> IO a
bar x = do
let y = x + 1
return y
let test :: Num a => IO a
test = do
(x,y) <- (bar 10, bar 20)
return y
Run Code Online (Sandbox Code Playgroud)
键入GHCI REPL时出现以下错误:
:29:15:
Couldn't match expected type ‘IO a1’ with actual type ‘(t0, …Run Code Online (Sandbox Code Playgroud) 我想用以下的符号表示糖.但我不确定我是否做得对:
方法是:
quote = do
time <- qtime
qcomma
ask <- double
qcomma
bid <- double
qcomma
askVolume <- double
qcomma
bidVolume <- double
endOfLine
return $ Quote time ask bid askVolume bidVolume
Run Code Online (Sandbox Code Playgroud)
和
quote = Quote <$> (qtime <* qcomma)
<*> (double <* qcomma)
<*> (double <* qcomma)
<*> (double <* qcomma)
<*> (double <* endOfLine)
Run Code Online (Sandbox Code Playgroud)
相当于:
qtime >>= (\time -> qcomma)
>> double
>>= (\ ask -> qcomma)
>> double
>>= (\bid -> qcomma)
>> double
>>= (\askVolume …Run Code Online (Sandbox Code Playgroud) 我正在尝试实现一个将字符串转换为Maybe Ints列表的函数,例如readInts "1 2 42 foo" = [Just 1,Just 2,Just 42,Nothing].
我的第一个方法是:
readInts (s::String) = do {
ws <- words s;
return (map (readMaybe::(String -> Maybe Int)) ws)
}
Run Code Online (Sandbox Code Playgroud)
这导致以下错误:
lab_monad.hs:20:52:
Couldn't match type ‘Char’ with ‘[Char]’
Expected type: [String]
Actual type: String
In the second argument of ‘map’, namely ‘ws’
In the first argument of ‘return’, namely
‘(map (readMaybe :: String -> Maybe Int) ws)’
Failed, modules loaded: none.
Run Code Online (Sandbox Code Playgroud)
我接下来(和工作)尝试的是:
readInts (s::String) = do {
let ws …Run Code Online (Sandbox Code Playgroud) 为什么下面的代码会产生错误parse error on input ‘putStrLn’?
main = do line <- fmap reverse getLine
putStrLn $ "You said " ++ line ++ " backwards!"
putStrLn $ "Yes, you said " ++ line ++ " backwards!"
<interactive>:11:4: error: parse error on input ‘putStrLn’
Run Code Online (Sandbox Code Playgroud)
另外,为什么以下代码会产生错误parse error on input ‘let’?
main = do line <- getLine
let line' = reverse line
putStrLn $ "You said " ++ line' ++ " backwards!"
putStrLn $ "Yes, you said " ++ line' ++ …Run Code Online (Sandbox Code Playgroud) 我正在提供这个问题的答案,我想到了使用Contmonad 的想法.我不知道Haskell足以解释为什么这个程序不起作用
import Control.Monad.Cont
fib1 n = runCont (slow n) id
where
slow 0 = return 0
slow 1 = return 1
slow n = do
a <- slow (n - 1)
b <- slow (n - 2)
return a + b
main = do
putStrLn $ show $ fib1 10
Run Code Online (Sandbox Code Playgroud)
错误 -
main.hs:10:18: error:
• Occurs check: cannot construct the infinite type: a2 ~ m a2
• In the second argument of ‘(+)’, namely ‘b’ …Run Code Online (Sandbox Code Playgroud) Haskell 2010年报告说
do表达式为monadic编程提供了更常规的语法。它允许一个表达式,例如
Run Code Online (Sandbox Code Playgroud)putStr "x: " >> getLine >>= \l -> return (words l)用更传统的方式写成:
Run Code Online (Sandbox Code Playgroud)do putStr "x: " l <- getLine return (words l)
汤普森说,Haskell函数编程技巧说
我们将继续使用do表示法,但要记住,它本质上 归结为一个函数(>> =)的存在,该函数负责对I / O程序进行排序并将其结果绑定以供将来使用。
以上是否意味着必须在monad的上下文中使用符号?
如果是,为什么以下函子使用do表示法?
instance Functor IO where
-- fmap :: (a -> b) -> IO a -> IO b
fmap g mx = do {x <- mx; return (g x)}
Run Code Online (Sandbox Code Playgroud) 我有用于我尚未编写的 Haskell 应用程序的输入数据,这些数据驻留在一个文件中。我不更新文件。我只需要读取文件并将其输入到需要字符串列表的 Haskell 函数中。但是读取文件当然会产生IO数据对象。我了解到使用该<-操作可以以某种方式“取出”打包在IO结构中的字符串,因此我尝试了以下尝试:
run :: [String]
run = do
datadef_content <- readFile "play.txt" -- yields a String
let datadef = lines datadef_content -- should be a [String]
return datadef
Run Code Online (Sandbox Code Playgroud)
我把它放到一个文件中play.hs,然后从 ghci 加载它
:l play
Run Code Online (Sandbox Code Playgroud)
令我惊讶的是,我收到了该readFile行的错误消息
Run Code Online (Sandbox Code Playgroud)Couldn't match type ‘IO’ with ‘[]’ Expected type: [String] Actual type: IO String
和return错误信息
Run Code Online (Sandbox Code Playgroud)Couldn't match type ‘[Char]’ with ‘Char’ Expected type: [String] Actual type: [[String]]
第一条似乎表明我无法摆脱IO,而最后一条消息似乎表明,这lines将返回一个字符串列表列表,这对我来说也没有意义。 …
我正在通过编写玩具语言来学习 Haskell。我想知道如何将 let 与嵌套 do 构造结合起来。我想写类似的东西(完全常见的用例,但在 do 表示法中使用 State-monad):
let x' = if special x then do ... else x
Run Code Online (Sandbox Code Playgroud)
更准确地说,我想写一些像这样的代码:
moveOpersToVirt :: [IOper] -> State (RegNum, M.Map OperNum Var, TRegs) [IOper]
moveOpersToVirt ((i, Oper op r arg1 arg2):os) = do
(virt_rn, mp, regs) <- get
let arg2' = if isRegGlobal arg2
-- get previously remembered value for "global reg arg2"
then getRegStrict regs (getValRegStrict arg2)
else arg2
let arg1' = ...
let r' = if isRegGlobal r
-- substitute …Run Code Online (Sandbox Code Playgroud) do-notation ×10
haskell ×10
monads ×6
io ×2
applicative ×1
file-read ×1
io-monad ×1
syntax ×1
syntax-error ×1