How to add a condition to a match in case ... of - elm

In functional languages, one can add a condition to a branch of a pattern matching: for example, in OCaml:
let value = match something with
| OneThing -> "1"
| Another when condition -> "2"
| _ -> "3"
How to do this in elm? I tried when and if, but nothing worked.

Elm does not have conditionals within pattern matching, probably because the language designers tend to prefer to keep syntax small and simple.
The best you can do is something like this:
let
value =
case something of
OneThing ->
"1"
Another ->
if condition then
"2"
else
...
_ ->
"3"

As an alternative to using an if within the case branch, you might want to instead match against a tuple containing the condition, which would look like this:
let
value =
case ( something, condition ) of
( OneThing, _ ) ->
"1"
( Another, True ) ->
"2"
_ ->
"3"

Related

Is there a way to pass the name of a field to a setter function?

Here I have several functions that all just set a single field on a model record.
In a more dynamic language, I'd just have a single setter function and pass it the name of the field (as a string) and the value that I want to set on the model object.
Is there a way to pass the name of the field in Elm?
What's the Elm way of doing something like this?
type alias Patient =
{ id : String
, name : String
, dateOfBirth : String
, sex : String
... other fields
}
setPatientName : Patient -> String -> Patient
setPatientName patient value =
{ patient | name = value }
setPatientDateOfBirth : Patient -> String -> Patient
setPatientDateOfBirth patient value =
{ patient | dateOfBirth = value }
setPatientSex : Patient -> String -> Patient
setPatientSex patient value =
{ patient | sex = value }
... many others
-- idx is the index of the patient in the model (which is an array of patients)
-- UpdateCell is a variant of my Msg type, like this: UpdateCell Int (Patient -> String -> Patient) String
onInputHandler : Int -> (Patient -> String -> Patient) -> String -> Msg
onInputHandler idx setter inputText =
UpdateCell idx setter inputText
-- idx is the index of the patient in the model (which is an array of patients)
createTableRow : Int -> Patient -> Html Msg
createTableRow idx patient =
...
, input [ type_ "text", onInput (onInputHandler idx setPatientName), value patient.name ] []
, input [ type_ "text", onInput (onInputHandler idx setPatientDateOfBirth), value patient.dateOfBirth ] []
...
I'm currently using each of these functions as an event handler for input elements. So I need a function that I can use for handling the input event. Ideally, I'd define just a single function and use that single one for all the input elements and pass it the field I want to update on the patient record.
The short answer is "no". But this seems a bit like an XY problem. It's not clear what benefit you are trying to achieve since the full application of such a function would be longer than the equivalent record update expression:
setField "name" patient value
-- vs
{ patient | name = value }
and as a partially applied function is only slightly shorter than the equivalent anonymous function with shortened argument names:
setField "name"
-- vs
\r x -> { r | name = x }
Although the latter is significantly noisier with all the symbols.
There is also a short-hand function for getting a record field:
.name
-- vs
\r -> r.name
So there is some precedent for having a dedicated syntax for setter functions too, but unfortunately there is not. Likely because it would complicate the language, and the syntax in particular, for relatively little benefit. I'm therefore curious about what you're actually trying to accomplish.
Edit after question update:
Putting functions in the Msg is a very bad idea because it goes against the Elm Architecture. It makes the state transition opaque and won't work very well with the debugger. When something goes wrong you can still see the state before and after, but you'll have trouble understanding what happened, and why it happened, because that information is encoded in an opaque function which probably isn't the one it should be.
You'll also have trouble factoring your logic. If you need something to happen only when a certain field updates, you might have to put the logic in the view, or special-case that field by putting the logic for that in update while the rest is in view, for example. Either way, you're on the path to a messy code base.
You should generally use names for messages that describe what happened, not what to do, because that tends to lead to an imperative mindset. Instead of UpdateCell you could call it InputChanged, for example. Then instead of the function you should have an identifier for the field. Ideally a custom type, like InputChanged Name, but even a string will work, though it will be much easier to miss a typo.
So instead of setter functions for each field you'll just case match the message and set the field in the update function:
InputChanged Name value ->
{ patient | name = value }
-- vs
setPatientName : Patient -> String -> Patient
setPatientName patient value =
{ patient | name = value }
Then if you need to clear the sex when the name changes, for example (because reasons...), you can simply do:
InputChanged Name value ->
{ patient | name = value, sex = "" }
The Elm Architecture is good because it makes changes easy and safe, not because it's concise and free of boiler-plate. Good Elm code often has a lot of copy-and-paste, but that's not always bad.

Why does the following case statement not work in the following loop?

Currently, I am writing a loop for a process that goes down a list of data and does certain things. I would like to use case statements to accomplish this.
What is wrong with my code? Is something wrong with my syntax?
Select Case me!Type
Case Me!Type Like "*Raytheon*"
Do Until myParts.EOF
rst_tbl_JString.New
rst_tbl_JString!Code = CodeString
rst_tbl_JString!Quantity = 1
rst_tbl_JString!Part = myParts!Part
rst_tbl_JString!Description = myParts!Description
rst_tbl_JString!Amount = myParts!Amount
rst_tbl_JString!Total = myParts!Amount
rst_tbl_JString.Update
Debug.Print JString!Part & " NEW "
myParts.MoveNext
Loop
End Select
With regards to:
Select Case me!Model
Case Me!Model Like "*Everflo*"
do something
The expression in the case is meant to be checked against the object in the select. Unfortunately, the expression in your case is a boolean value (is something like something else), so will be unlikely to match any value in me!Model. What you effectively have is:
If me!Model = (Me!Model Like "*Everflo*")
do something
The use case for select/case tends to be more of the form:
Select Case me!Model
Case "Everflow"
do something
so that the case expression can be correctly matched against the selectobject.
I think the best solution in this case (since you're doing "looks like" rather than "is equal to" comparisons) is just to revert to a simpler conditional construct:
If Me!Model Like "*Everflo*"
do something
ElseIf Me!Model Like "*Platinum*"
do something else
End If

If statement for vbnet

I want to make an if statement with conditions that have 2 result
Example
if (id = "25" OR "36") then
print "The id is 25 or 36"
else
print "the id is not 25 or 36"
end if
My concern is in the if condition statement for "OR"
I try with "AND" but this only takes id = 25 as true whereas id = 36 as false
I try with "OR" "ORELSE" "XOR" this takes everything as true.
I try || sign but I got syntax error
You are missing the comparision after the or:
If (id = "25" Or id = "36") Then
You need to provide the variable to check each time
If id = "25" or id = "36" Then
Alternatively, if this is likely to expand to include other numbers, you could use
If {"25","36"}.Contains(id) Then
Alternatively, you could use a Select Case statement:
Select Case id
Case "25", "36"
Print("The id is 25 or 36")
Case Else
Print("The id is not 25 or 36")
End Select
This works the same way as an if..else statement, but allows you to easily supply different test expressions.

Handling multiple match cases with single statement in Elm

I know in Scala you can handle multiple patterns with a single expression, is something like this possible in Elm?
l match {
case B(_) | C(_) => "B"
}
In Elm, you can only match upon one pattern at a time, unless you are pattern matching on the underscore character, which catches all.
case l of
B _ -> "B"
C _ -> "B"
...
-- or...
case l of
...
_ -> "B"
If you have something more complex that a string, it is probably best to pull it into its own function:
let
doB -> "B"
in
case l of
B _ -> doB
C _ -> doB
...
You can do something similar to the following
sample expression =
case expression of
Case1 -> "String"
Case2 -> sample Case1
Case3 -> sample Case1

What would be the RegularExpression for the followings?

I have a nomenclature to respect while performing some tasks against the Active Directory.
Here's the nomenclature:
TT-EEE-Mnemonic: if TT = 'GA' or 'GS' or 'PA' or 'PF' -> the schema to create is a "group", with a groupScope of Global.
LT-EEE-Mnemonic: if T = 'A' or 'G' or 'I' or 'N' or 'P' -> the schema to create is a "group", with a groupScope of Domain local.
TTT-EEE-Mnemonic: if TTT* = 'CNX' or 'GST' or 'SVC' -> the shema to create is an "user"
T-SSSS-Mnemonic: if T = 'A' or 'L' or 'M' or 'R' or 'S' -> the schema to create is an "organizationUnit"
What I'm after is a simpler and more effective way than this:
If(dn.Substring(3, 2).Contains("GA") _
Or variable.Substring(3, 2).Contains("GS") _
Or dn.Substring(3, 2).Contains("PA") _
Or dn.Substring(3, 2).Contains("PF")) Then
schema = "group" ' Global'
Else If(dn.Substring(4, 1).Contains("A") _
Or dn.Substring(4, 1).Contains("G") _
Or dn.Substring(4, 1).Contains("I") _
Or dn.Substring(4, 1).Contains("N") _
Or dn.Substring(4, 1).Contains("P")) Then
schema = "group" ' Local'
Else If(dn.Substring(3, 3).Contains("CNX") _
' Well... You get the idea, don't you?
End If
I guess I could use a RegularExpression, or perhaps one for each of the nomenclature I got, something alike.
Is there a way a RegularExpression could become handy in this situation? Or would it be best to stick with that old big-If? Any suggestions are welcome.
Sorry for asking, but I'm not used to use RegularExpression. I know they exist, and bit of what they can do, but that's all.
Thanks!
Your code does not seem to conform your description. With your description, you may want the following regular expression:
^(((GA|GS|PA|PF)|L[AGINP]|(CNX|GST|SVC))-EEE|[ALRMS]-SSSS)$
EDIT: you may want to read up this tutorial about what the regular expression means, specifically look for the "Character classes" and "Grouping and alternatives" sections.
In short, the bar character (i.e. |) is the "OR" operator. The square brackets (i.e. []) are the character class; in other words, "OR" between the characters.
It'd vastly reduce the number of tests and explicit Ors.
If Regex.IsMatch(dn, "^CN=(G[AS]|P[AF])-") Then
schema = "group" ' Global 'damn syntax highlighting
ElseIf Regex.IsMatch(dn, "^CN=L[AGINP]-") Then
schema = "group" ' Local 'damn syntax highlighting
ElseIf Regex.IsMatch(dn, "^CN=(CNX|GST|SVC)-") Then
schema = "user"
ElseIf Regex.IsMatch(dn, "^CN=[ALMRS]-") Then
schema = "organizationUnit"
End If
How about...
Dim Schema As String = Nothing
Select Case dn.SubString(3, 2) ' Am not sure about your index of 3 here!
Case "GA", "GS", "PA", "PS"
Schema = "group"
End Select
If IsNothing(Schema) Then
Select Case ...
End If
etc.