【问题标题】:Compilation error: "The last statement in a 'do' construct must be an expression"编译错误:“'do' 构造中的最后一条语句必须是表达式”
【发布时间】:2012-05-24 18:22:28
【问题描述】:

以下是我就餐哲学家的代码并产生一个编译错误,指出“'do' 构造中的最后一条语句必须是一个表达式:mVar2

import Control.Concurrent
import Control.Concurrent.MVar
import System.Random

takefork :: Int -> forks -> IO ()
takefork n forks = takeMVar (forks!!n)

releasefork :: Int -> forks -> IO ()
releasefork n forks = putMVar (forks!!n)

philosopher :: [Int]
philosopher = [1,2,3,4,5]

forks :: [MVar] -> [Int]
forks = do
    takefork n ( philosopher - 1)
    threadDelay delay
    let delay = 100000
    takefork n philosopher
    putStrLn("Philosopher" ++ philosopher ++ "has started eating")
    releasefork n philosopher
    releasefork n ( philosopher - 1)
    ptStrLn ("Philosopher" ++ philosopher ++ "has stopped eating")
    forks

main :: IO ()
main = do
    mVar1 <- newEmptyMVar
    mVar2 <- newEmptyMVar
    mVar3 <- newEmptyMVar
    mVar4 <- newEmptyMVar
    mVar5 <- newEmptyMVar
    let mVar = [mVar1, mVar2, mVar3, mVar4, mVar5]
    sequence_ [ forkIO forks (mVar philosopher) ]

【问题讨论】:

  • 由于许多可能与您的问题无关的原因,这无法编译,您能解决它们吗? (例如,“16:14: Not in scope: 'n'”)
  • 它在范围内。我不明白为什么它不适合你。
  • 好吧,不是的! n 需要被定义为全局变量或作为forks 的函数参数,两者都不是。这不是唯一的问题。 — 请务必复制您所询问的程序完全正确
  • 嗯,我不明白为什么会这样。在我的程序中,我所做的只是调用我在 forks 中定义的函数,并使其成为递归函数。我觉得我的主要问题是在实现 main 时出现的。
  • takefork n ( philosopher - 1) 行中,n 是从哪里来的?它没有在任何地方声明。此外,您将philosopher 视为一个数字,但事实并非如此。代码还有很多其他问题。

标签: haskell dining-philosopher


【解决方案1】:

你的代码有很多问题。

您报告的错误消息表明您可能混合使用了空格和制表符。去掉制表符,只使用空格。


您可能编写这个程序是为了练习编写 Haskell 程序,而不是为了娱乐和盈利而运行该程序。因此,我们不想简单地为您提供一个有效的 Dining Philosophers 实现,我们希望帮助您编写您的实现。

我无法从您的代码中看出您期望它如何工作。

我将专注于最后一行:

sequence_ [ forkIO forks (mVar philosopher) ]

sequence_ :: [IO a] -&gt; IO () --- 给sequence_ 一个 i/o 动作列表,它(返回一个 i/o 动作)按顺序执行每个动作。从[...] 看来,您正在尝试给它一个列表,但只有一个元素。这可能不是你的意思。

forkIO :: IO () -&gt; IO ThreadID --- 给forkIO 一个 i/o 操作,它(返回一个 i/o 操作)启动该 i/o 操作在一个新线程中运行,并为您提供该线程的 id。

这里有两个问题:

  • forks 是一个函数,而不是一个 i/o 操作(它甚至不是一个返回 i/o 操作的函数,尽管您可能是认真的)
  • 你给forkIO第二个参数((mVar philosopher)),但它只需要一个参数

mVar philosopher 本身没有任何意义:mVar :: [MVar a](这是一个 MVar 列表,我还没有弄清楚 MVar 应该包含什么类型)但是你把它当作一个函数,传递它philosopher 作为参数。

此时,我头顶上的一个灯泡闪烁。您希望使用参数mVarphilosopher 调用forks

sequence_ [ forkIO (forks mVar philosopher) ]

不过,我们仍在对单个操作进行排序。也许您希望依次调用forksphilosopher 的每个元素?

sequence_ $ map (\n -> forkIO (forks mVar n)) philosopher

我们可以将其简化为

mapM_ (\n -> forkIO (forks mVar n)) philosopher

这与您给forks :: [MVar] -&gt; [Int] 的类型不匹配。但这可能是错误的,因此您接下来需要修复该功能。

【讨论】:

  • 代码确实包含选项卡,如果您“编辑”帖子并选择一些空格,则可以看到。
  • 是的,我注意到了这一点并修复了标签问题。我想做的是使用哲学家列表中的数字takefork n (philosopher - 1) 我试图更好地理解如何使用这个数字。
  • 这真的很有帮助。非常感谢。此时我意识到forks :: [MVar] -&gt; [Int] 中提供的数字参数与所需的参数不匹配。我假设上面的函数应该返回一个 IO 动作。如果我错了,请纠正我。谢谢
  • 不,没错。我希望你想要forks :: [MVar] -&gt; Int -&gt; IO ()
  • 我无法定义n。在forks函数内部,声明变量n时,应该声明为let n =什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多