简体   繁体   中英

Haskell pattern matching error with data constructor

I have the following code in 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))

The definition of ProgT is defined in the module 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 

Put simply, Seq[StmtT] is a list of Assign, If or While statements defined in the constructor. The function changeName checks if there are variables in ALL statements that equal to x, and replaces it with y. When I run the code, I get the following error:

Assignment3.hs:12:89: error: • Couldn't match type 'StmtT' with '[ProgT]' Expected type: [ProgT] Actual type: ProgT • In the second argument of '(:)', namely 'changeName xy (Seq moreStatements)' In the first argument of 'Seq', namely '(changeName xy oneStatement : changeName xy (Seq moreStatements))' In the expression: Seq (changeName xy oneStatement : changeName xy (Seq moreStatements))

Based on the error message, the problem is in the last line:

changeName xy (Seq (oneStatement:moreStatements)) = Seq(changeName xy oneStatement: changeName xy (Seq moreStatements) )

I can see why it would throw the error, but I have to recurse through each statement to change every variable in the statements. Apologies if this is trivial, but I don't know I could recurse through Seq[StmtT] types without the error.

note: I don't think it matters what the other data types are (ie BExprT), just in case here is more of the module:

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)]

EDIT: @Ben Using map helped get around the error (since the function does not return a list now).

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

Should be:

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

Specifically the problem is that the last part where you have changeName xy Seq(moreStatements) is seen as applying changeName to 4 arguments:

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

Seq(moreStatements) doesn't mean "apply Seq to moreStatements , as it would in a language with C-like syntax, but is rather just the terms Seq (moreStatements) next to each other, completely equivalent to if you had written Seq moreStatements because the parentheses are not needed to group a single identifier. If Seq was the "head" of that sub-expression it would do what you want, but it follows on changeName xy , so that is applied to Seq , and then to moreStatements , which doesn't fit the type of changeName .

(Note that this is pretty much exactly what the error message said)


Your second error is that changeNames has type String -> String -> ProgT -> ProgT (and remember ProgT = StmtT ). But you use the result of changeName on the right side of : , as if it returned a list of something.

Probably you need to instead changeName over the list, rather than applying it to the head and to the tail? In fact you wouldn't even need to pattern match on the list then, you could just:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM