Haskell数据域中的多态性

Haskell数据域中的多态性,haskell,polymorphism,field,chess,maybe,Haskell,Polymorphism,Field,Chess,Maybe,我试图通过创建一个简单的国际象棋游戏来学习Haskell。但是,我在定义表示电路板正方形的函数时遇到了问题 import Data.Char type Board = [[Square]] type Square = Maybe Piece data Piece = Piece PieceColor PieceType deriving (Show, Eq) data PieceColor = White | Black deriving (Show, Eq) data PieceType =

我试图通过创建一个简单的国际象棋游戏来学习Haskell。但是,我在定义表示电路板正方形的函数时遇到了问题

import Data.Char
type Board = [[Square]]
type Square = Maybe Piece
data Piece = Piece PieceColor PieceType deriving (Show, Eq)
data PieceColor = White | Black deriving (Show, Eq)
data PieceType = King | Queen | Rook | Bishop | Knight | Pawn deriving (Show, Eq)

...    

displaySquare :: Square -> Char
    displaySquare n
        | n == Nothing = ' '
        | n == Just (Piece White _) = displaySquare' n
        | otherwise = toLower (displaySquare' n)
            where
                displaySquare'   (Just (Piece _ King))   = 'K'
                displaySquare'   (Just (Piece _ Queen))  = 'Q'
                displaySquare'   (Just (Piece _ Rook))   = 'R'
                displaySquare'   (Just (Piece _ Bishop)) = 'B'
                displaySquare'   (Just (Piece _ Knight)) = 'N'
                displaySquare'   (Just (Piece _ Pawn))   = 'P'
尝试运行GHCI将返回以下错误:

Chess.hs:21:30:
    Found hole ‘_’ with type: PieceType
    Relevant bindings include
      displaySquare' :: Maybe Piece -> Char (bound at Chess.hs:24:13)
      n :: Square (bound at Chess.hs:19:15)
      displaySquare :: Square -> Char (bound at Chess.hs:19:1)
    In the second argument of ‘Piece’, namely ‘_’
    In the first argument of ‘Just’, namely ‘(Piece White _)’
    In the second argument of ‘(==)’, namely ‘Just (Piece White _)’
Failed, modules loaded: none.

我不太清楚错误是想告诉我什么。如果我不得不猜测的话,我会说问题是将数据字段定义为一个洞“z”,因为这意味着函数可以将任何类型作为数据字段,这显然与给定的类型签名冲突。我的假设正确吗?我应该如何解决它?

这是使用模式匹配编写
displaySquare
的方法:

displaySquare Nothing = ' '
displaySquare n@(Just (Piece White _)) = displaySquare' n
displaySquare n                        = toLower (displaySquare' n)
  where
    ...your definition of displaySquare'...
您在定义
displaySquare'
时正确使用了模式匹配

注意语法
n@(Just(Piece White))
是如何工作的——它提供了一个模式来匹配:
Just White
,并且它还将变量
n
设置为传递给函数的参数

更新

@behzad.nouri在评论中提到,您需要将helper函数置于顶层

另一种使助手函数保持本地的写入方法:

displaySquare n =
  case n of
    Nothing              -> ' '
    Just (Piece White _) -> displaySquare' n
    _                    -> toLower (displaySquare' n)
  where
    displaySquare' x = ...

在这种情况下,
n
绑定到
displaySquare
的第一个参数,因此不需要使用
n@...
语法。

这是使用模式匹配编写
displaySquare
的方法:

displaySquare Nothing = ' '
displaySquare n@(Just (Piece White _)) = displaySquare' n
displaySquare n                        = toLower (displaySquare' n)
  where
    ...your definition of displaySquare'...
您在定义
displaySquare'
时正确使用了模式匹配

注意语法
n@(Just(Piece White))
是如何工作的——它提供了一个模式来匹配:
Just White
,并且它还将变量
n
设置为传递给函数的参数

更新

@behzad.nouri在评论中提到,您需要将helper函数置于顶层

另一种使助手函数保持本地的写入方法:

displaySquare n =
  case n of
    Nothing              -> ' '
    Just (Piece White _) -> displaySquare' n
    _                    -> toLower (displaySquare' n)
  where
    displaySquare' x = ...

在这种情况下,
n
绑定到
displaySquare
的第一个参数,因此不需要使用
n@...
语法。

关键是:模式匹配的工作原理与相等比较根本不同(通常更可取)

通过模式匹配,您只需查看片段数据是否“适合您感兴趣的粗略形状”。您可以完全忽略您不感兴趣的部分数据,就像您尝试使用
Just(Piece White)
一样。因此,模式匹配通常是一种“模糊操作”

OTOH,
=
只是一个运算符(),它接受两个值并确定它们是否完全相等
Piece White实际上不是一个值,您需要给出一个具体的
PieceType
,以适应
\uCode>间隙。这就是GHC试图用type:PieceType
告诉你的信息
发现了一个洞“uu”:如果你真的需要建立一个
平方
值,你需要提供一个
PieceType
值。当你处理复杂问题时,这些键入的孔非常有用:只需从外部开始,例如,你可以从
n==Piece\uuu
开始,GHC会告诉你它期望在第一个间隙中有一个
PieceColor
,你会插入
White
,GHC会告诉你它期望在第二个间隙中有一个
PieceType
,等等

只是,在
displaySquare
函数中,实际上构造一个具体的
Square
值来进行比较是没有意义的:您真正想要做的是解构这些值。这就是模式匹配更方便的地方。事实上,我会把这个函数写成一个大的子句列表:

displaySquare (Just (Piece White King))   = '♔'
displaySquare (Just (Piece White Queen))  = '♕'
displaySquare (Just (Piece White Rook))   = '♖'
displaySquare (Just (Piece White Bishop)) = '♗'
displaySquare (Just (Piece White Knight)) = '♘'
displaySquare (Just (Piece White Pawn))   = '♙'
displaySquare (Just (Piece Black pt))
   = toEnum . (+6)  -- Unicode U+2659 WHITE CHESS PAWN
                    --  is followed by BLACK CHESS KING, etc.
      . fromEnum . displaySquare . Just $ Piece White pt
displaySquare Nothing = ' '

关键是:模式匹配的工作原理与相等比较的工作原理根本不同(通常更可取)

通过模式匹配,您只需查看片段数据是否“适合您感兴趣的粗略形状”。您可以完全忽略您不感兴趣的部分数据,就像您尝试使用
Just(Piece White)
一样。因此,模式匹配通常是一种“模糊操作”

OTOH,
=
只是一个运算符(),它接受两个值并确定它们是否完全相等
Piece White实际上不是一个值,您需要给出一个具体的
PieceType
,以适应
\uCode>间隙。这就是GHC试图用type:PieceType
告诉你的信息
发现了一个洞“uu”:如果你真的需要建立一个
平方
值,你需要提供一个
PieceType
值。当你处理复杂问题时,这些键入的孔非常有用:只需从外部开始,例如,你可以从
n==Piece\uuu
开始,GHC会告诉你它期望在第一个间隙中有一个
PieceColor
,你会插入
White
,GHC会告诉你它期望在第二个间隙中有一个
PieceType
,等等

只是,在
displaySquare
函数中,实际上构造一个具体的
Square
值来进行比较是没有意义的:您真正想要做的是解构这些值。这就是模式匹配更方便的地方。事实上,我会把这个函数写成一个大的子句列表:

displaySquare (Just (Piece White King))   = '♔'
displaySquare (Just (Piece White Queen))  = '♕'
displaySquare (Just (Piece White Rook))   = '♖'
displaySquare (Just (Piece White Bishop)) = '♗'
displaySquare (Just (Piece White Knight)) = '♘'
displaySquare (Just (Piece White Pawn))   = '♙'
displaySquare (Just (Piece Black pt))
   = toEnum . (+6)  -- Unicode U+2659 WHITE CHESS PAWN
                    --  is followed by BLACK CHESS KING, etc.
      . fromEnum . displaySquare . Just $ Piece White pt
displaySquare Nothing = ' '

这将无法编译,因为助手函数不在第2行的作用域中。它还会抛出一个错误,因为
n@(仅白色)
应该是
n@(仅白色)
。但是,修复这个问题并将helper函数定义为常规函数是可行的!出于好奇,有没有办法定义helper函数,使其保留在displaySquare中?用谷歌搜索多个函数的helper函数似乎并没有带来任何效果。答案很好!使用
case
可以让它更有效可读。@NicolásSiplis您还可以保留其他防护装置(并避免移动辅助功能)