Hi I am confused about the usage of the match operator. I have come across a snippet of code that looks nothing like the explanation on the documentation: https://docs.mulesoft.com/mule-runtime/3.9/dataweave-operators#match
%function testMatch(key)
(key match {
x when x is :null -> false,
x when x == "A" -> true,
x when x == "B" -> false,
x when x == "J" -> true,
x when x == "K" -> false,
x when x == "L" -> true,
default -> false
})
Please help understand the meaning of this syntax for match
Great question! The match keyword serves two purposes in DataWeave, and it depends on its placement. Match is either used for regex, or pattern matching.
match for Regex
If match has a string on the left-hand side (lhs) and a regex on the rhs, it will operate according to the following docs. Basically, it's doing regex matching:
Match returns an array that contains the entire matching expression, followed by all of the capture groups that match the provided regex.
match for Pattern Matching
If match has anything that evaluates to a value (i.e., does not evaluate to a function) on the lhs and an open bracket on the rhs, match is now doing pattern matching. You can find that docs for that here. I cover this pretty extensively in the talk I did, you can find the slides for that here.
For the example you provided (nice formatting, btw):
%function testMatch(key)
(key match {
x when x is :null -> false,
x when x == "A" -> true,
x when x == "B" -> false,
x when x == "J" -> true,
x when x == "K" -> false,
x when x == "L" -> true,
default -> false
})
match is checking if its input, x, is null, A, B, J, K, or L. If it matches any of those, DW will evaluate what's on the rhs of the arrow, and return immediately. If nothing matches, it will return what is on the rhs of the arrow for default.
Related
So I have a custom programming language, and in it I am doing some math formalization/modeling. In this instance I am doing basically this (a pseudo-javascript representation):
isIntersection([1, 2, 3], [1, 2], [2, 3]) // => true
isIntersection([1, 2, 3], [1, 2, 3], [3, 4, 5]) // => false
function isIntersection(setTest, setA, setB) {
i = 0
while (i < setTest.length) {
let t = setTest[i]
if (includes(setA, t) || includes(setB, t)) {
i++
} else {
return false
}
}
return true
}
function includes(set, element) {
for (x in set) {
if (isEqual(element, x)) {
return true
}
}
return false
}
function isEqual(a, b) {
if (a is Set && b is Set) {
return isSetEqual(a, b)
} else if (a is X... && b is X...) {
return isX...Equal(a, b)
} ... {
...
}
}
function isSetEqual(a, b) {
i = 0
while (i < a.length) {
let x = a[i]
let y = b[i]
if (!isEqual(x, y)) {
return false
}
i++
}
return true
}
The isIntersection is checking isEqual, and isEqual is configured to be able to handle all kinds of cases of equality check, from sets compared to sets, objects to objects, X's to X's, etc..
The question is, how can we make the isEqual somehow ignorant of the implementation details? Right now you have to have one big if/else/switch statement for every possible type of object. If we add a new type, we have to modify this gigantic isEqual method to add support for it. How can we avoid this, and just define them separately and cleanly?
I was thinking initially of making the objects be "instances of classes" so to speak, with class methods. But I like the purity of having everything just be functions and structs (objects without methods). Is there any way to implement this sort of thing without using classes with methods, instead keeping it just functions and objects?
If not, then how would you implement it with classes? Would it just be something like this?
class Set {
isEqual(set) {
i = 0
while (i < this.length) {
let x = this[i]
let y = set[i]
if (!x.isEqual(y)) {
return false
}
i++
}
return true
}
}
This would mean every object would have to have an isEqual defined on it. How does Haskell handle such a system? Basically looking for inspiration on how this can be most cleanly done. I want to ideally avoid having classes with methods.
Note: You can't just delegate to == native implementation (like assuming this is in JavaScript). We are using a custom programming language and are basically trying to define the meaning of == in the first place.
Another approach is to pass around an isEqual function along with everything somehow, though I don't really see how to do this and if it were possible it would be clunky. So not sure what the best approach is.
Haskell leverages its type and type-class system to deal with polymorphic equality.
The relevant code is
class Eq a where
(==) :: a -> a -> Bool
The English translation is: a type a implements the Eq class if, and only if, it defines a function (==) which takes two inputs of type a and outputs a Bool.
Generally, we declare certain "laws" that type-classes should abide by. For example, x == y should be identical to y == x in all cases, and x == x should never be False. There's no way for the compiler to check these laws, so one typically just writes them into the documentation.
Once we have defined the typeclass Eq in the above manner, we have access to the (==) function (which can be called using infix notation - ie, we can either write (==) x y or x == y). The type of this function is
(==) :: forall a . Eq a => a -> a -> Bool
In other words, for every a that implements the typeclass Eq, (==) is of type a -> a -> Bool.
Consider an example type
data Boring = Dull | Uninteresting
The type Boring has two proper values, Dull and Uninteresting. We can define the Eq implementation as follows:
instance Eq Boring where
Dull == Dull = True
Dull == Uninteresting = False
Uninteresting == Uninteresting = True
Uninteresting == Dull = False
Now, we will be able to evaluate whether two elements of type Boring are equal.
ghci> Dull == Dull
True
ghci> Dull == Uninteresting
False
Note that this is very different from Javascript's notion of equality. It's not possible to compare elements of different types using (==). For example,
ghci> Dull == 'w'
<interactive>:146:9: error:
* Couldn't match expected type `Boring' with actual type `Char'
* In the second argument of `(==)', namely 'w'
In the expression: Dull == 'w'
In an equation for `it': it = Dull == 'w'
When we try to compare Dull to the character 'w', we get a type error because Boring and Char are different types.
We can thus define
includes :: Eq a => [a] -> a -> Bool
includes [] _ = False
includes (x:xs) element = element == x || includes xs element
We read this definition as follows:
includes is a function that, for any type a which implements equality testing, takes a list of as and a single a and checks whether the element is in the list.
If the list is empty, then includes list element will evaluate to False.
If the list is not empty, we write the list as x : xs (a list with the first element as x and the remaining elements as xs). Then x:xs includes element iff either x equals element, or xs includes element.
We can also define
instance Eq a => Eq [a] where
[] == [] = True
[] == (_:_) = False
(_:_) == [] = False
(x:xs) == (y:ys) = x == y && xs == ys
The English translation of this code is:
Consider any type a such that a implements the Eq class (in other words, so that (==) is defined for type a). Then [a] also implements the Eq type class - that is, we can use (==) on two values of type [a].
The way that [a] implements the typeclass is as follows:
The empty list equals itself.
An empty list does not equal a non-empty list.
To decide whether two non-empty lists (x:xs) and (y:ys) are equal, check whether their first elements are equal (aka whether x == y). If the first elements are equal, check whether the remaining elements are equal (whether xs == ys) recursively. If both of these are true, the two lists are equal. Otherwise, they're not equal.
Notice that we're actually using two different ==s in the implementation of Eq [a]. The equality x == y is using the Eq a instance, while the equality xs == ys is recursively using the Eq [a] instance.
In practice, defining Eq instances is typically so simple that Haskell lets the compiler do the work. For example, if we had instead written
data Boring = Dull | Uninteresting deriving (Eq)
Haskell would have automatically generated the Eq Boring instance for us. Haskell also lets us derive other type classes like Ord (where the functions (<) and (>) are defined), show (which allows us to turn our data into Strings), and read (which allows us to turn Strings back into our data type).
Keep in mind that this approach relies heavily on static types and type-checking. Haskell makes sure that we only ever use the (==) function when comparing elements of the same type. The compiler also always knows at compile type which definition of (==) to use in any given situation because it knows the types of the values being compared, so there is no need to do any sort of dynamic dispatch (although there are situations where the compiler will choose to do dynamic dispatch).
If your language uses dynamic typing, this method will not work and you'll be forced to use dynamic dispatch of some variety if you want to be able to define new types. If you use static typing, you should definitely look into Haskell's type class system.
This question already has answers here:
What makes reference comparison (==) work for some strings in Java?
(6 answers)
Closed 4 years ago.
According to the docs, === performs referential equality.
Given the following referential equality comparisons, this doesn't seem to work in all cases:
val x = "A"
val y = "A"
println(x === y) // "true"
println("A" === "A") // "true"
I would expect both of those cases to return false.
Yet this example returns false as expected:
val x = readLine()!! // "A"
val y = readLine()!! // "A"
println(x === y) // "false"
So why does referential equality comparison work for the latter case, but not the former?
The === basically means "are these objects of the same type and do they point to the same memory address?"
In your first example, both x and y point to a constant A, which, as a String constant, there is a single instance of, so they return true.
When you read from a file, an allocation takes place for the string read, and thus, x and y point to different memory addresses, so they are equal (== returns true), but not identical (=== return false).
After learning how to pass regexes as arguments, I've tried to build my first regex using a sub, and I'm stuck once more. Sorry for the complex rules below, I've made my best to simplify them. I need at least some clues how to approach this problem.
The regex should consist of alternations, each of them consisting of left, middle and right, where left and right should come in pairs and the variant of middle depends on which right is chosen.
An array of Pairs contains pairs of left and right:
my Pair #leftright =
A => 'a',
...
Z => 'z',
;
Middle variants are read from a hash:
my Regex %middle =
z => / foo /,
a => / bar /,
m => / twi /,
r => / bin /,
...
;
%middle<z> should be chosen if right is z, %middle<a> — if right is a, etc.
So, the resulting regex should be
my token word {
| A <%middle[a]> a
| Z <%middle[z]> z
| ...
}
or, more generally
my token word {
| <left=#leftright[0].key>
<middle=%middle{#leftright[0].value}>
<right=#leftright[0].value>
| (the same for index == 1)
| (the same for index == 2)
| (the same for index == 3)
...
}
and it should match Abara and Zfooz.
How to build token word (which can be used e.g. in a grammar) with a sub that will take every pair from #leftright, put the suitable %middle{} depending on the value of right and then combine it all into one regex?
my Regex sub sub_word(Pair #l_r, Regex %m) {
...
}
my token word {
<{sub_word(#leftright, %middle)}>
}
After the match I need to know the values of left, middle, and right:
"Abara" ~~ &word;
say join '|', $<left>, $<middle>, $<right> # A|bar|a
I was not able to do this using token yet, but here is a solution with EVAL and Regex (and also I am using %middle as a hash of Str and not a hash of Regex):
my Regex sub build_pattern (%middle, #leftrigth) {
my $str = join '|', #leftright.map(
{join ' ',"\$<left>='{$_.key}'", "\$<middle>='{%middle{$_.value}}'", "\$<right>='{$_.value}'"});
);
my Regex $regex = "rx/$str/".EVAL;
return $regex;
}
my Regex $pat = build_pattern(%middle, #leftright);
say $pat;
my $res = "Abara" ~~ $pat;
say $res;
Output:
rx/$<left>='A' $<middle>='bar' $<right>='a'|$<left>='Z' $<middle>='foo' $<right>='z'/
「Abara」
left => 「A」
middle => 「bar」
right => 「a」
For more information on why I chose to use EVAL, see How can I interpolate a variable into a Perl 6 regex?
In Idris, is it possible to rewrite all functions using "with" to use "case" instead of "with" ?
If not, could you give a counter example ?
Not possible. When you pattern match with with, the types in the context are updated with information extracted from the matched constructor. case doesn't cause such updating.
As an example, the following works with with but not with case:
import Data.So
-- here (n == 10) in the goal type is rewritten to True or False
-- after the match
maybeTen : (n : Nat) -> Maybe (So (n == 10))
maybeTen n with (n == 10)
maybeTen n | False = Nothing
maybeTen n | True = Just Oh
-- Here the context knows nothing about the result of (n == 10)
-- after the "case" match, so we can't fill in the rhs
maybeTen' : (n : Nat) -> Maybe (So (n == 10))
maybeTen' n = case (n == 10) of
True => ?a
False => ?b
I have the following code:
doSomething : (s : String) -> (not (s == "") = True) -> String
doSomething s = ?doSomething
validate : String -> String
validate s = case (not (s == "")) of
False => s
True => doSomething s
After checking the input is not empty I would like to pass it to a function which accepts only validated input (not empty Strings).
As far as I understand the validation is taking place during runtime
but the types are calculated during compile time - thats way it doesn't work. Is there any workaround?
Also while playing with the code I noticed:
:t (("la" == "") == True)
"la" == "" == True : Bool
But
:t (("la" == "") = True)
"la" == "" = True : Type
Why the types are different?
This isn't about runtime vs. compile-time, since you are writing two branches in validate that take care, statically, of both the empty and the non-empty input cases; at runtime you merely choose between the two.
Your problem is Boolean blindness: if you have a value of type Bool, it is just that, a single bit that could have gone either way. This is what == gives you.
= on the other hand is for propositional equality: the only constructor of the type(-as-proposition) a = b is Refl : a = a, so by pattern-matching on a value of type a = b, you learn that a and b are truly equal.
I was able to get your example working by passing the non-equality as a proposition to doSomething:
doSomething : (s : String) -> Not (s = "") -> String
doSomething "" wtf = void $ wtf Refl
doSomething s nonEmpty = ?doSomething
validate : String -> String
validate "" = ""
validate s = doSomething s nonEmpty
where
nonEmpty : Not (s = "")
nonEmpty Refl impossible
As far as I understand the validation is taking place during runtime
but the types are calculated during compile time - thats way it
doesn't work.
That's not correct. It doesn't work because
We need the with form to perform dependent pattern matching, i. e. perform substitution and refinement on the context based on information gained from specific data constructors.
Even if we use with here, not (s == "") isn't anywhere in the context when we do the pattern match, therefore there's nothing to rewrite (in the context), and we can't demonstrate the not (s == "") = True equality later when we'd like to call doSomething.
We can use a wrapper data type here that lets us save a proof that a specific pattern equals the original expression we matched on:
doSomething : (s : String) -> (not (s == "") = True) -> String
doSomething s = ?doSomething
data Inspect : a -> Type where
Match : {A : Type} -> {x : A} -> (y : A) -> x = y -> Inspect x
inspect : {A : Type} -> (x : A) -> Inspect x
inspect x = Match x Refl
validate : String -> String
validate s with (inspect (not (s == "")))
| Match True p = doSomething s p
| Match False p = s