【问题标题】:Haskell pattern matching error with data constructor数据构造函数的 Haskell 模式匹配错误
【发布时间】:2017-08-04 05:53:11
【问题描述】:

我在 Haskell 中有以下代码:

module testData where

import SImpL
changeName :: String -> String -> ProgT -> ProgT
...
changeName x y (Seq []) = Seq[]
changeName x y (Seq (oneStatement:moreStatements)) = Seq (changeName x y oneStatement : changeName x y (Seq moreStatements))

ProgT的定义在模块SImpL中定义:

data StmtT = Assign NameT AExprT |   
             If BExprT StmtT StmtT | 
             While BExprT StmtT | 
             Seq [StmtT] -- If the list is empty, this is a statement that does nothing.    
             deriving (Show,Eq)

type ProgT = StmtT 

简单地说,Seq[StmtT] 是一个在构造函数中定义的 Assign、If 或 While 语句的列表。 函数 changeName 检查所有语句中是否有变量等于 x,并将其替换为 y。 当我运行代码时,我收到以下错误: p>

Assignment3.hs:12:89: 错误: • 无法将类型“StmtT”与“[ProgT]”匹配 预期类型:[ProgT] 实际类型:ProgT • 在‘(:)’的第二个参数中,即 ‘changeName x y (Seq moreStatements)’ 在“Seq”的第一个参数中,即 '(changeName x y oneStatement : changeName x y (Seq moreStatements))’ 在表达式中: 序列 (changeName x y oneStatement : changeName x y (Seq moreStatements))

根据错误信息,问题出在最后一行:

changeName x y (Seq (oneStatement:moreStatements)) = Seq(changeName x y oneStatement:changeName x y (Seq moreStatements))

我知道它为什么会抛出错误,但我必须通过每个语句递归来更改语句中的每个变量。抱歉,如果这是微不足道的,但我不知道我可以通过 Seq[StmtT] 类型进行递归而不会出现错误。

注意:我认为其他数据类型是什么(即 BExprT)并不重要,以防万一这里有更多模块:

module SImpL where

data AExprT = ALit ValT -- a literal value (an Int)
              | AName NameT -- a variable name (a String)
              | Add AExprT AExprT -- one arithmetic expression added to another
              | Sub AExprT AExprT -- one arithmetic expression subtracted from another
              | Mult AExprT AExprT -- one arithmetic expression multiplied by another
              deriving (Show,Eq)

data BExprT = BLit Bool -- a literal value (True or False)
              | Eq AExprT AExprT -- an equality test between two arithmetic expressions
              | Less AExprT AExprT -- a "less than" test between two arithmetic expressions
              | Greater AExprT AExprT -- a "greater than" test between two arithmetic expressions
              | Not BExprT -- the negation of a boolean expression
              | And BExprT BExprT -- the "and" of two boolean expressions
              | Or BExprT BExprT -- the "or" of two boolean expressions
              deriving (Show,Eq)

type ValT = Integer

type NameT = String 

data StmtT = Assign NameT AExprT |   
             If BExprT StmtT StmtT | 
             While BExprT StmtT | 
             Seq [StmtT] -- If the list is empty, this is a statement that does nothing.    
             deriving (Show,Eq)  

If BExprT StmtT StmtT | 
             While BExprT StmtT | 
             Seq [StmtT] -- If the list is empty, this is a statement that does nothing.    
             deriving (Show,Eq)

type ProgT = StmtT 

type StateT = [(NameT, ValT)]

编辑: @Ben 使用 map 帮助解决了错误(因为该函数现在不返回列表)。

【问题讨论】:

    标签: haskell


    【解决方案1】:
    changeName x y (Seq (oneStatement:moreStatements)) = Seq(changeName x y oneStatement:changeName x y Seq(moreStatements))
    

    应该是:

    changeName x y (Seq (oneStatement:moreStatements)) = Seq (changeName x y oneStatement : changeName x y (Seq moreStatements))
    

    具体问题在于,您拥有changeName x y Seq(moreStatements) 的最后一部分被视为将changeName 应用于4 个参数:

    1. x
    2. y
    3. Seq
    4. (moreStatements)

    Seq(moreStatements) 并不意味着“将Seq 应用于moreStatements,就像在具有类C 语法的语言中那样,而是只是术语Seq (moreStatements) 彼此相邻,完全相当于如果你写了Seq moreStatements,因为括号不需要对单个标识符进行分组。如果Seq是那个子表达式的“头”,它会做你想做的事情,但它会跟随changeName x y,所以它应用于Seq,然后应用于moreStatements,它不适合changeName的类型。

    (请注意,这几乎就是错误消息所说的内容)


    您的第二个错误是changeNames 的类型为String -> String -> ProgT -> ProgT(请记住ProgT = StmtT)。但是您在: 的右侧使用changeName 的结果,就好像它返回了一个list 的东西。

    您可能需要将changeName 覆盖在列表上,而不是将其应用于头部和尾部?事实上,你甚至不需要在列表上进行模式匹配,你可以:

    changeName x y (Seq statements) = Seq (map (changeName x y) statements)
    

    【讨论】:

    • 谢谢,但我在换括号时仍然遇到错误,即:Could't match type 'StmtT' with '[ProgT]' Expected type: [ProgT] Actual type : ProgT • 在'(:)'的第二个参数中,即'changeName xy (Seq moreStatements)'
    • @RosaryLightningX 我已经编辑了我的答案来解决这个问题,尽管它在技术上是一个完全独立的错误,只是被第一个错误所掩盖。
    • 啊,是的,改变方法确实有帮助——现在模式匹配编译正确。我根本没想过使用地图而不是头部和尾部,非常感谢您的洞察力。
    猜你喜欢
    • 1970-01-01
    • 2018-06-09
    • 1970-01-01
    • 2012-04-29
    • 2021-12-31
    • 2021-02-12
    • 1970-01-01
    • 1970-01-01
    • 2016-04-26
    相关资源
    最近更新 更多