Elm Syntax, Pipe forward a match case without using temp variable - elm

F#, Pipe forward a match case without using temp variable
Similar to the question above, is there a way to pipe-forward a variable to a match case without using a temp variable or a lambda?
The idea:
let temp =
x
|> Function1
|> Function2
// ........ Many functions later.
|> FunctionN
in
result =
case temp of
Case1 -> "Output 1"
Case2 -> "Output 2"
_ -> "Other Output"
I hope to achieve the following:
result =
x
|> Function1
|> Function2
// ........ Many functions later.
|> FunctionN
|> case of // Syntax Error! Should use "case temp of"
Case1 -> "Output 1"
Case2 -> "Output 2"
_ -> "Other Output"
I can use a lambda function, but I would still be "naming" the temp variable.
result =
x
|> Function1
|> Function2
// ........ Many functions later.
|> FunctionN
|> \temp -> case temp of
Case1 -> "Output 1"
Case2 -> "Output 2"
_ -> "Other Output"
Is there a way in the Elm syntax to "get rid" of the temp variable? Thanks.

No, Elm does not have that ability.
Other languages like Haskell allow something similar via the LambdaCase extension, but Elm tends to avoid having too many ways to say the same thing, erring on the side of keeping syntax simple.
The issue has been raised before, and Elm's author rejected the proposal with the following comment:
More generally though, the focus right now is not on growing the syntax of Elm. (We're actually dropping stuff more often.) If something can be expressed in Elm already, I'm not hugely interested in providing alternate ways to express it. In this case, I think we would be adding syntax to make things less regular and harder to read.

Related

Elm syntax help required

Could you please explain me what does mean in Elm next statement?
(=>) = (,)
I found it in the example of Elm architecture tutorial
This is infix notation. In effect, this defines a function
(=>) = \a b -> (a,b)
Infix is then used without the brackets, so
a => b == (a,b)

Right way to forcibly convert Maybe a to a in Elm, failing clearly for Nothings

Okay, what I really wanted to do is, I have an Array and I want to choose a random element from it. The obvious thing to do is get an integer from a random number generator between 0 and the length minus 1, which I have working already, and then applying Array.get, but that returns a Maybe a. (It appears there's also a package function that does the same thing.) Coming from Haskell, I get the type significance that it's protecting me from the case where my index was out of range, but I have control over the index and don't expect that to happen, so I'd just like to assume I got a Just something and somewhat forcibly convert to a. In Haskell this would be fromJust or, if I was feeling verbose, fromMaybe (error "some message"). How should I do this in Elm?
I found a discussion on the mailing list that seems to be discussing this, but it's been a while and I don't see the function I want in the standard library where the discussion suggests it would be.
Here are some pretty unsatisfying potential solutions I found so far:
Just use withDefault. I do have a default value of a available, but I don't like this as it gives the completely wrong meaning to my code and will probably make debugging harder down the road.
Do some fiddling with ports to interface with Javascript and get an exception thrown there if it's Nothing. I haven't carefully investigated how this works yet, but apparently it's possible. But this just seems to mix up too many dependencies for what would otherwise be simple pure Elm.
(answering my own question)
I found two more-satisfying solutions:
Roll my own partially defined function, which was referenced elsewhere in the linked discussion. But the code kind of feels incomplete this way (I'd hope the compiler would warn me about incomplete pattern matches some day) and the error message is still unclear.
Pattern-match and use Debug.crash if it's a Nothing. This appears similar to Haskell's error and is the solution I'm leaning towards right now.
import Debug
fromJust : Maybe a -> a
fromJust x = case x of
Just y -> y
Nothing -> Debug.crash "error: fromJust Nothing"
(Still, the module name and description also make me hesitate because it doesn't seem like the "right" method intended for my purposes; I want to indicate true programmer error instead of mere debugging.)
Solution
The existence or use of a fromJust or equivalent function is actually code smell and tells you that the API has not been designed correctly. The problem is that you're attempting to make a decision on what to do before you have the information to do it. You can think of this in two cases:
If you know what you're supposed to do with Nothing, then the solution is simple: use withDefault. This will become obvious when you're looking at the right point in your code.
If you don't know what you're supposed to do in the case where you have Nothing, but you still want to make a change, then you need a different way of doing so. Instead of pulling the value out of the Maybe use Maybe.map to change the value while keeping the Maybe. As an example, let's say you're doing the following:
foo : Maybe Int -> Int
foo maybeVal =
let
innerVal = fromJust maybeVal
in
innerVal + 2
Instead, you'll want this:
foo : Maybe Int -> Maybe Int
foo maybeVal =
Maybe.map (\innerVal -> innerVal + 2) maybeVal
Notice that the change you wanted is still done in this case, you've simply not handled the case where you have a Nothing. You can now pass this value up and down the call chain until you've hit a place where it's natural to use withDefault to get rid of the Maybe.
What's happened is that we've separated the concerns of "How do I change this value" and "What do I do when it doesn't exist?". We deal with the former using Maybe.map and the latter with Maybe.withDefault.
Caveat
There are a small number of cases where you simply know that you have a Just value and need to eliminate it using fromJust as you described, but those cases should be few and far between. There's quite a few that actually have a simpler alternative.
Example: Attempting to filter a list and get the value out.
Let's say you have a list of Maybes that you want the values of. A common strategy might be:
foo : List (Maybe a) -> List a
foo hasAnything =
let
onlyHasJustValues = List.filter Maybe.isJust hasAnything
onlyHasRealValues = List.map fromJust onlyHasJustValues
in
onlyHasRealValues
Turns out that even in this case, there are clean ways to avoid fromJust. Most languages with a collection that has a map and a filter have a method to filter using a Maybe built in. Haskell has Maybe.mapMaybe, Scala has flatMap, and Elm has List.filterMap. This transforms your code into:
foo : List (Maybe a) -> List a
foo hasAnything =
let
onlyHasRealValues = List.filterMap (\x -> x) hasAnything
in
onlyHasRealValues

Context sensitive grammar

Noam Chomsky - formal languages - type 1 - context sensitive grammar
Does AB->BA violate the rule? I assume it does.
A -> aAB does not violate condition?
aAB->ABc violates condition?
Using the wikipedia link provided, you can answer each question if you can map your production rules to the form:
iAr -> ibr, where A is a single non-terminal, i and r are (possibly empty) strings of terminals and non-terminals, and b is a non-empty string of terminals and non-terminals.
In other words, look at each of your rules, and try to make suitable choices for i, A, r, and b.
Before we look at your questions, let's look at some hypothetical examples:
Is CRC -> CRRRRRC a valid context-sensitive rule?
Yes. I can choose i=empty, A=C, r=RC, and b=CRRRR. Note, I could have made other choices that work, too.
Is xYz -> xWzv a valid context-sensitive rule?
No. There is no choice for i, A, and r that allow a match. If I chose i=x A=Y, r=z, and b=W, that trailing v screws things up.
Is xY -> xWzv a valid context-sensitive rule?
Yes. I can choose i=x, A=Y, r=empty, and b=Wzv.
This is the scheme you should use to answer your questions. Now, let's look at those:
AB -> BA: Assume you choose either A or B to be your single non-terminal. The choice fixes i and r (one will be empty, the other will be the non-terminal you didn't choose). Is there a string of the form ibr that can match based on how you fixed i and r? In other words, can you choose the string to replace b that maps to your rule?
A -> aAB. I hope the choice of your single non-terminal on the left is intuitively obvious. This choice will again fix i and r. Does the right map to a suitable ibr form where b is a nonempty string of terminals and nonterminals?
aAB -> ABc. Again, choose A or B to be your single non-terminal. This fixes i and r. Is there a choice that allows you to choose a suitable ibr?

(partial apply str) and apply-str in clojure's ->

If I do the following:
user=> (-> ["1" "2"] (partial apply str))
#<core$partial__5034$fn__5040 clojure.core$partial__5034$fn__5040#d4dd758>
...I get a partial function back. However, if I bind it to a variable:
user=> (def apply-str (partial apply str))
#'user/apply-str
user=> (-> ["1" "2" "3"] apply-str)
"123"
...the code works as I intended it. I would assume that they are the same thing, but apparently that isn't the case. Can someone explain why this is to me?
-> is a macro, so it doesn't have to follow the rules you would expect in terms of application. The macro transforms the source before the forms are evaluated. Try macroexpanding the forms:
user> (macroexpand '(-> ["1" "2"] (partial apply str)))
(partial ["1" "2"] apply str)
What are you trying to achieve here by using the '->' macro?
EDIT: Note that:
user> ((partial apply str) ["1" "2"])
"12"
You don't have to do that at all.
(->> ["1" "2" "3"] (apply str))
Why not do that instead?
The first expression, (-> ["1" "2"] (partial apply str)), expands into:
(partial ["1" "2"] apply str) which basically means:
Create a function from ["1" "2"] (which is also a function, since vectors are functions of index keys!) with the Vars apply and str already supplied as the first two arguments. This function gets printed as the weird #<core$partial...> string.
Only when this function will be called will you get an IllegalArgumentException since vectors only take one integer argument, not two Var arguments.
The Macro -> Threads the expr through the forms as second argument. In your case ends up in expanding to: (partial ["1" "2"] apply str), creating a parital function based on vector.
But you want to invoke a parital function based on apply and str on the threaded expr and thus need:
(-> ["1" "2"] ((partial apply str)))
Well: this code i quite confusing and not idiomatic Clojure.
The -> macro adds parens around apply-str in your second version, that's why the macro expands to code that ends up calling your function. Look at the source code for -> and you can see:
(defmacro ->
"Threads the expr through the forms. Inserts x as the
second item in the first form, making a list of it if it is not a
list already. If there are more forms, inserts the first form as the
second item in second form, etc."
([x] x)
([x form] (if (seq? form)
(with-meta `(~(first form) ~x ~#(next form)) (meta form))
(list form x)))
([x form & more] `(-> (-> ~x ~form) ~#more)))
The relevant part is when it's dealing with two arguments, x and form. If form is a seq, x is inserted as the second argument in that list. Otherwise, the macro puts form and x it into a list itself. This is so you can use a bare symbol as shorthand for a list containing one symbol.
user> (macroexpand '(-> 123 (foo)))
(foo 123)
user> (macroexpand '(-> 123 foo))
(foo 123)

F# Generate SQL from CSV

I have recently been learning F# and functional programming. One application I have found very useful is generating SQL inserts for a data load from a CSV (or excel table) with some associated ID's.
The following code is my result, which I believe I will find very handy in the future. I thought others could also benefit from this and I welcome suggestions and other scripts which people have found invaluable in their collection:
// Returns some dataload SQL for area mapping.
open System
open System.IO
// Read and split CSV into lists
let map_ngo_area = File.ReadAllLines(#"P:\MY_TABLE.csv")
|> Array.to_list
|> List.map(fun x -> (x.Split([|','|])
|> Array.map(fun y -> y.Trim()))
|> Array.to_list)
// Output Formatting function
let format_sql_record = "INSERT INTO MyTable
(ID, REF1_ID, REF2_ID, CreatedUser, CreatedDateTime, LastModifiedUser, LastModifiedDateTime)
VALUES
( {0}, {1}, {2}, 'system', getDate(), 'system', getDate() )"
// Generate the SQL for the given list.
let generate_sql list = list |> List.mapi(fun index row ->
match row with
| [ngo_id; area_id] -> String.Format(format_sql_record, ((int index)+1), ngo_id, area_id) |> printfn "%s"
| _ -> printfn "")
// Main Execution
map_ngo_area |> generate_sql |> ignore
// End of program, pause to view console output.
System.Console.ReadKey() |> ignore
Any suggestions on improving my F# code or process? Comments also welcome, as I am fairly new at this paradigm and shifting thinking is not as forthcoming as I expected.
Thanks :)
Here are a few suggestions:
Don't use List.mapi with functions that return unit, since there's not much you can do with the resulting unit list. You should use List.iteri instead, which will allow you to omit the |> ignore at the end of your main execution section.
Going further, rather than having generate_sql print the generated lines one at a time, it might be better to generate a list of strings instead. Note that in this case, you would go back to using List.mapi since the function that you apply would return a result for each line.
Use F#'s print formatting rather than String.Format. For instance rather than having format_sql_record be a string, have it be a function of type int->string->string->string: let format_sql_record = sprintf "INSERT INTO ... VALUES (%i, %s, %s, ...)"
Depending on the version of F# that you're using, you should probably be using the renamed function Array.toList instead of Array.to_list, since that's the name that will be used in the final release of F#.
You can use pattern matching on arrays too:
let map_ngo_area = File.ReadAllLines(#"P:\MY_TABLE.csv")
|> Array.to_list
|> List.map(fun x -> (x.Split([|','|])
|> Array.map(fun y -> y.Trim()))
let generate_sql list = list |> List.mapi(fun index row ->
match row with
| [| ngo_id; area_id |] -> printfn ...
| _ -> printfn "")