Haskell pattern matching

I tried to find a list of pairs that could have an element ("$", Undefined) in it in some arbitrary place. I wanted to ONLY search for the part of the list before this special element, so I tried something like this (there is already an intention to take the element n and the list xs as arguments):

checkNotSameScope :: Env -> VarName -> Expr -> Expr checkNotSameScope (xs:("$", Undefined):_) ne = if alreadyThere n xs then BoolLit False else BoolLit True 

But this does not work; the compiler seemed to indicate that (xs: ..) uses only one value adding my list. I can not use: to indicate the first fragment of the list; only one item. Looking back, it makes sense; otherwise, how did the compiler know what to do? Adding "s" to something like "x" does not magically create multiple elements! But how can I get around this?

+1
source share
3 answers

Unfortunately, even with smart compilers and languages, some programs cannot be fixed ...

In your case, it seems to you that part of the list corresponds to a specific element. More generally, you can use the standard takeWhile library to find a list to a certain condition. Then you can simply run alreadyThere on it:

 checkNotSameScope :: Env -> VarName -> Expr -> Expr checkNotSameScope xs ne = if alreadyThere n (takeWhile (/= ("$", Undefined)) xs) then BoolLit False else BoolLit True 

Perhaps this is not what you want for lists where ("$", Undefined) does not exist, so be careful.

+5
source

As in Joachim's answer, you can use break , which allows you to detect when ("$", Undefined) does not happen (if necessary). i.e.

 checkNotSameScope xs ne = case break (== ("$", Undefined)) xs of (_, []) -> .. -- ("$", Undefined) didn't occur! (xs', _) -> BoolLit . not $ alreadyThere n xs' 

(NB, you are losing some laziness in this decision, since the list must go to ("$", Undefined) or to the end to check the first case.)

+2
source

Haskell cannot do this kind of pattern matching out of the box, although there are some languages ​​that can, for example, CLIPS , for example, or F #, using active patterns .

But we can use the existing Haskell pattern matching capabilities to get a similar result. First, define a function called deconstruct, defined as follows:

 deconstruct :: [a] -> [([a], a, [a])] deconstruct [] = [] deconstruct [x] = [([], x, [])] deconstruct (x:xs) = ([], x, xs) : [(x:ys1, y, ys2) | (ys1, y, ys2) <- deconstruct xs] 

What this function does is get all the decompositions of the list xs into triples of the form (ys1, y, ys2) such that ys1 ++ [y] ++ ys2 == xs . For example:

 deconstruct [1..4] => [([],1,[2,3,4]),([1],2,[3,4]),([1,2],3,[4]),([1,2,3],4,[])] 

Using this, you can define your function as follows:

 checkNotSameScope xs ne = case [ys | (ys, ("$", Undefined), _) <- deconstruct xs] of [ys] -> BoolLit $ not $ alreadyThere n xs _ -> -- handle the case when ("$", Undefined) doesn't occur at all or more than once 

We can use do-notation to get something even closer to what you are looking for:

 checkNotSameScope xs ne = BoolLit $ not $ any (alreadyThere n) prefixes where prefixes = do (xs, ("$", Undefined), _) <- deconstruct xs return xs 

Here are a few things going on. First of all, the prefixes variable will store all the prefix lists that appear before the pair ("$", Undefined) , or not if the pair is not in the xs input list. Then, using the any function, we check to see if alreadyThere n True for any of the prefixes. The rest is to complete your function logic.

0
source

Source: https://habr.com/ru/post/1441885/


All Articles