在 haskell 中请求输入的函数(在 do 块中打印)
Function asking for Input in haskell (with print in do block)
我是 haskell 的新手,我正在尝试实现一个简单的 connect4 游戏,当我尝试让玩家输入新动作时,我想提示他这样做。这是我的相关代码:
advanceHuman :: Board -> Board
advanceHuman b = do
let column = query
if (snd((possibleMoves b)!!(column-1)) == cha)
then updateBoard b p1 column
else advanceHuman b
query :: Int
query = do {
print ("escoge una columna vacia") ; -- choose empty column
input <- getLine ;
return (read input) }
如您所见,我尝试提示玩家,得到他的答案并将其传递给其他功能(假设玩家会合作并输入有效数字)。
但是,这是我尝试编译时收到的错误消息
* Couldn't match expected type `Int' with actual type `IO b0'
* In a stmt of a 'do' block: print ("escoge una columna vacia")
In the expression:
do print ("escoge una columna vacia")
input <- getLine
return (read input)
In an equation for `query':
query
= do print ("escoge una columna vacia")
input <- getLine
return (read input)
|
47 | print ("escoge una columna vacia") ;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
根据我的理解,我应该能够在 do 块中打印一行,而不管该函数输出的是什么?有什么问题,我是不是误解了 "do" 的工作原理?
UPDT
应要求,这些是涉及的其他功能
possibleMoves:: Board -> Board
possibleMoves b = take sx b
updateBoard:: Board -> String -> Int -> Board
updateBoard b pl col = b
Updateboard 尚未实现,因此它只有一些伪代码来安抚编译器
p1 cha 和 sx 是事先声明的全局常量
基本上我砍掉棋盘的顶部以检查哪些列已满('_' = 空),检查玩家使用 "query" 指定的列的顶部以查看其是否合法移动;如果没有,该过程将重新开始。
Haskell 不使用大括号来限定代码范围。相反,它是通过缩进完成的。 return 与您在命令式编程中发现的典型 return 语句不同。它实际上在做的是将您的值包装在 monad 类型中。您可以在 GHCI 中查看:
Prelude> :t return
return :: Monad m => a -> m a
do
表示法是一种组合单子动作的方法。如果没有很多我不会在这里讨论的理论,很难解释这意味着什么。 (我建议你拿起一本 haskell 的书)。它只是语法糖,没有它你也能过得去(我将在下面展示)。
至少要修复您的代码:
query :: (IO Int)
query = do
print ("escoge una columna vacia")
input <- getLine
return (read input)
IO 是一种当 Int 应用于它时成为类型的类型。类型是 (IO Int)
这是没有做的代码:
module Examples where
query :: (IO Int)
query =
print ("escoge una columna vacia") >>
getLine >>= (\x ->
return (read x))
我建议您查看 >> 和 >>= 的作用。一般来说,你应该避免函数 read
它是一个不安全的函数(如果你输入的是字符串而不是 int 会怎样?)还有其他更安全的函数不假设你已经实现了类型类
monad 的理论非常有趣,值得您深入研究并深入理解。但这里有一个大部分错误的答案,可帮助您开始编码而不必担心所有这些。
有两种东西,值和动作。操作的类型包含在 IO
中,例如 IO Int
、IO String
、IO (Maybe [Bool])
。行动就是你做事的方式 I/O。他们做了一些 I/O,完成后,他们 return 他们包装的类型的值。
动作是用 do
构造的,通常最后一行有 return <value>
(或者是另一个动作,在这种情况下它使用那个动作的 return 值)。所以你的 query
是一个动作:
query :: IO Int -- notice the IO
query = do
print ("escoge una columna vacia")
input <- getLine
return (read input)
你使用动作的方式是绑定它们使用<-
,你已经用getLine
完成了。这只能在 do
块中完成。所以当你想在advanceHuman
中使用query
时,你需要绑定它:
advanceHuman b = do
input <- query
...
绑定左侧的名称(或模式)变为 值 类型,无论包装在 IO
中 - 在本例中为 Int
.
不过,我说的是do
构造动作。这意味着 advanceHuman
需要 return 一个动作类型:
advanceHuman :: Board -> IO Board
advanceHuman b = do
input <- query
...
唯一可以在 do 块中作为行的是动作,绑定或不绑定值,以及 return <value>
(事实证明,这也是一个动作)。
您必须先绑定动作,然后才能使用它们的值。例如。如果你有
getX :: IO Int
getY :: IO Int
那么你不能说 getX + getY
来得到他们的总和。你必须说 do { x <- getX; y <- getY; return (x + y) }
(或 liftA2 (+) getX getY
,但我们不要太过分了)。
如果您想将名称绑定到 值 而不是动作,请改用 let
。所以在 advanceHuman
中你使用了 let
而你应该使用 <-
因为 query
是一个动作。
希望这对您有所帮助。
我是 haskell 的新手,我正在尝试实现一个简单的 connect4 游戏,当我尝试让玩家输入新动作时,我想提示他这样做。这是我的相关代码:
advanceHuman :: Board -> Board
advanceHuman b = do
let column = query
if (snd((possibleMoves b)!!(column-1)) == cha)
then updateBoard b p1 column
else advanceHuman b
query :: Int
query = do {
print ("escoge una columna vacia") ; -- choose empty column
input <- getLine ;
return (read input) }
如您所见,我尝试提示玩家,得到他的答案并将其传递给其他功能(假设玩家会合作并输入有效数字)。 但是,这是我尝试编译时收到的错误消息
* Couldn't match expected type `Int' with actual type `IO b0'
* In a stmt of a 'do' block: print ("escoge una columna vacia")
In the expression:
do print ("escoge una columna vacia")
input <- getLine
return (read input)
In an equation for `query':
query
= do print ("escoge una columna vacia")
input <- getLine
return (read input)
|
47 | print ("escoge una columna vacia") ;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
根据我的理解,我应该能够在 do 块中打印一行,而不管该函数输出的是什么?有什么问题,我是不是误解了 "do" 的工作原理?
UPDT
应要求,这些是涉及的其他功能
possibleMoves:: Board -> Board
possibleMoves b = take sx b
updateBoard:: Board -> String -> Int -> Board
updateBoard b pl col = b
Updateboard 尚未实现,因此它只有一些伪代码来安抚编译器
p1 cha 和 sx 是事先声明的全局常量
基本上我砍掉棋盘的顶部以检查哪些列已满('_' = 空),检查玩家使用 "query" 指定的列的顶部以查看其是否合法移动;如果没有,该过程将重新开始。
Haskell 不使用大括号来限定代码范围。相反,它是通过缩进完成的。 return 与您在命令式编程中发现的典型 return 语句不同。它实际上在做的是将您的值包装在 monad 类型中。您可以在 GHCI 中查看:
Prelude> :t return
return :: Monad m => a -> m a
do
表示法是一种组合单子动作的方法。如果没有很多我不会在这里讨论的理论,很难解释这意味着什么。 (我建议你拿起一本 haskell 的书)。它只是语法糖,没有它你也能过得去(我将在下面展示)。
至少要修复您的代码:
query :: (IO Int)
query = do
print ("escoge una columna vacia")
input <- getLine
return (read input)
IO 是一种当 Int 应用于它时成为类型的类型。类型是 (IO Int)
这是没有做的代码:
module Examples where
query :: (IO Int)
query =
print ("escoge una columna vacia") >>
getLine >>= (\x ->
return (read x))
我建议您查看 >> 和 >>= 的作用。一般来说,你应该避免函数 read
它是一个不安全的函数(如果你输入的是字符串而不是 int 会怎样?)还有其他更安全的函数不假设你已经实现了类型类
monad 的理论非常有趣,值得您深入研究并深入理解。但这里有一个大部分错误的答案,可帮助您开始编码而不必担心所有这些。
有两种东西,值和动作。操作的类型包含在 IO
中,例如 IO Int
、IO String
、IO (Maybe [Bool])
。行动就是你做事的方式 I/O。他们做了一些 I/O,完成后,他们 return 他们包装的类型的值。
动作是用 do
构造的,通常最后一行有 return <value>
(或者是另一个动作,在这种情况下它使用那个动作的 return 值)。所以你的 query
是一个动作:
query :: IO Int -- notice the IO
query = do
print ("escoge una columna vacia")
input <- getLine
return (read input)
你使用动作的方式是绑定它们使用<-
,你已经用getLine
完成了。这只能在 do
块中完成。所以当你想在advanceHuman
中使用query
时,你需要绑定它:
advanceHuman b = do
input <- query
...
绑定左侧的名称(或模式)变为 值 类型,无论包装在 IO
中 - 在本例中为 Int
.
不过,我说的是do
构造动作。这意味着 advanceHuman
需要 return 一个动作类型:
advanceHuman :: Board -> IO Board
advanceHuman b = do
input <- query
...
唯一可以在 do 块中作为行的是动作,绑定或不绑定值,以及 return <value>
(事实证明,这也是一个动作)。
您必须先绑定动作,然后才能使用它们的值。例如。如果你有
getX :: IO Int
getY :: IO Int
那么你不能说 getX + getY
来得到他们的总和。你必须说 do { x <- getX; y <- getY; return (x + y) }
(或 liftA2 (+) getX getY
,但我们不要太过分了)。
如果您想将名称绑定到 值 而不是动作,请改用 let
。所以在 advanceHuman
中你使用了 let
而你应该使用 <-
因为 query
是一个动作。
希望这对您有所帮助。