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 "")
Related
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.
This is related to the Elm Tutorials (http://guide.elm-lang.org/architecture/effects/random.html), and am trying to generate a list of random numbers (just 2 items for now) for one of the challenges.
I get a type error when trying to generate the list:
The 2nd argument to function `generate` is causing a mismatch.
39| Random.generate NewFaces intList)
^^^^^^^
Function `generate` is expecting the 2nd argument to be:
Random.Generator List
But it is:
Random.Generator (List Int)
This is the code I am using:
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
Roll ->
let
intList : Random.Generator (List Int)
intList =
Random.list 2 (Random.int 1 6)
in
(model, Random.generate NewFaces intList)
NewFaces newFaces ->
({ model | dieFaces = newFaces}, Cmd.none)
I am still trying to get my head wrapped around types -- particularly with regard to lists. I'm guessing (List Int) means a list of integers, but I am not sure what List by itself means (list of arbitrary type?).
I have played around with the code by pulling out the Generator into a separate variable (intList) and also explicitly typing it. I also tried typing it Random.Generator List, which throws an error also. Basically, I could use help figuring out how to reconcile List vs. (List Int).
Thank you -- super new to Elm, so any guidance is appreciated.
Based on the error message, it looks like you probably have defined NewFaces like this:
type Msg
= Roll
| NewFaces List
List takes a single type parameter, so it should be defined as
type Msg
= Roll
| NewFaces (List Int)
To me, adding "Dump" to the end of an expression doesn't seem to do anything different, at least for seeing rows in a table. Can you point me to an example of where it is handy?
If you are just working with an expression, there is no reason to call Dump—it's called automatically. But, in the language selection box, LINQPad allows allows the selection of Statements and Program. Once you select one of those, you don't get any Dump output unless you call it.
With Statements or Programs, you might want to call Dump on multiple times. In those cases, it is handy to pass the Description parameters so you can distinguish the output.
There are also other parameters you can use to shape the output, such as depth, which limits the substructure details.
Simple example (Language=C# Statements):
var integers = Enumerable.Range(1,10);
integers.Select(i => new { i, v = i * i}).Dump("Squares");
integers.Select(i => new { i, v = i * i * i}).Dump("Cubes");
var output = "λ is awesome";
Encoding.UTF8.GetBytes(output)
.Dump("UTF-8");
Encoding.GetEncoding("Windows-1252").GetBytes(output)
.Dump("Windows-1252 (lossy)");
I'm trying to make a program in SML that will read in a series/list/sequence of numbers from the user, process the numbers, and output the result. I don't know how many numbers the user will input. The program can either read in all the numbers and output the results all together or read and output one at a time. I don't care whether the input is in a separate file or manually input at a console.
What do I need to do to be able to read input?
fun fact x = if x<2 then 1 else x*fact(x-1);
let val keepgoing:bool ref = ref true in
while !keepgoing do
let val num = valOf(TextIO.inputLine TextIO.stdIn) in
print( Int.toString( fact( valOf( Int.fromString( num ) ) ) ) );
keepgoing := (null(explode(num)))
end
end;
Sorry about the convoluted conversions. If you also know an easier way to read in integers, I'd appreciate that, too.
Your logic is just flawed here. You want keepgoing := not (null (explode num)). Right? It works fine for me with that change. You need to implement removal of the final newline (so null explode does what you want) and parsing a line with more than one number, but you basically have the right idea.
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)