SalmaFG
SalmaFG

Reputation: 2192

Concatenating strings together into a list

What I'm trying to do is that I want to take a list of strings as input and do some operations then return back a list of strings. The problem is, I am looking for specific yet generic patterns of the string for each case:

func :: [String] -> [String]
func [] = []
func [x] = [x]
func (["Not","(","Not"]:es:[")"]) = es  --HERE
func ("Not":"(":pred:"And":rest:")") = ("Not":pred:"Or":(pushNotInwards rest))
func ("Not":"(":pred:"Or":rest:")") = ("Not":pred:"And":(pushNotInwards rest))
func ("Not":"(":"ForAll":x:scope:")") = ("Exists":"Not":"("scope:")")
func ("Not":"(":"Exists":x:scope:")") = ("ForAll":"Not":"(":scope:")")

For the third case for instance, I want to take a list of strings in the form of:

["Not","(","Not",some_strings,")"]

I tried using ++ on the left hand side as:

func (["Not"]++["("]++["Not"])++es++[")"]) = es

I also tried concat and : but they didn't work either. Any suggestions?

Upvotes: 0

Views: 106

Answers (2)

Haitham Gad
Haitham Gad

Reputation: 1579

You seem to have some confusion about the different string operators.

A String is just a synonym for a list of chars i.e. [Char]. The colon : operator (aka cons) adds one element to the beginning of a list. Here's its type:

*Main> :t (:)
(:) :: a -> [a] -> [a]

For example:

*Main> 1:[2,3]
[1,2,3]
*Main> 'a':"bc"
"abc"

The ++ operator concatenates two lists. Here's its type:

*Main> :t (++)
(++) :: [a] -> [a] -> [a]

Pattern matching can only be done using a data constructor. The : operator is a data constructor, but the ++ operator is not. So you cannot define a function using pattern matching over the ++ operator.

To define a function using pattern matching, I'd suggest defining a new data type for the different functions and qualifier rather than using strings:

-- Logic Operation
data LogicOp =
    Not LogicOp | And [LogicOp] | Or [LogicOp] |
    Forall String LogicOp | Exists String LogicOp | T | F
  deriving (Eq, Show)

func :: LogicOp -> LogicOp
func (Not (Not x)) = x
func (Not (And (pred:rest))) = Or (Not pred:[func (Not (And rest))])
func (Not (Or  (pred:rest))) = And (Not pred:[func (Not (Or rest))])
func (Not (Forall x scope)) = Exists x (Not scope)
func (Not (Exists x scope)) = Forall x (Not scope)
func x = x

Here are some examples:

*Main> func (Not (Not T))
T
*Main> func (Not (And [T, F, T]))
Or [Not T,Or [Not F,Or [Not T,Not (And [])]]]
*Main> func (Not (Or [T, F, T]))
And [Not T,And [Not F,And [Not T,Not (Or [])]]]
*Main> func (Not (Forall "x" (And T F))
*Main> func (Not (Forall "x" (And [T, F])))
Exists "x" (Not (And [T,F]))
*Main> func (Not (Exists "x" (And [T, F])))
Forall "x" (Not (And [T,F]))

Upvotes: 3

Johannes Kuhn
Johannes Kuhn

Reputation: 15163

You should probably not use strings for that. Create a new type:

 data SomeExpr = Not SomeExpr
               | And SomeExpr SomeExpr
               | Or  SomeExpr SomeExpr
               deriving (Show)

Then you could match on that expression:

 func :: SomeExpr -> SomeExpr
 func (Not (Not x)) = func x
 func (Not (And x y)) = Or (Not $ func x) (Not $ func y)
 func (Not (Or  x y)) = And (Not $ func x) (Not $ func y)
 ...
 func x = x

You can't pattern match a list in the middle, e.g You want to match [1,2,3,4,5] with (1:middle:5:[]), but this is invalid.

Yes, using an own type has it's own problems, you have to parse it etc, but it is much more easier and safer than with strings (which could have arbitrary content).

Upvotes: 2

Related Questions