Is there something similar to list comprehensions in Elm? - elm

If I understood it correctly Elm doesn't have something like list comprehension.
What would you use instead if you for example would like to map the numbers 1 to 100 to something else?

I think List.range and pipeline style read very well togeher.
But it is not as succinct as a list comprehension in python.
module Main exposing (main)
import Html
main =
List.range 1 10
|> List.map square
|> List.map String.fromInt
|> String.join ", "
|> Html.text
square : Int -> Int
square a =
a ^ 2

Related

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

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.

Type conflict when generating a random list of integers in Elm

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)

"Cannot find pattern" when using a tagged union type

I have an app that spans multiple modules. In the first, I model my problem, creating several data types. In the second, I'm putting views.
One of those types is a tagged union type:
type alias Letter = Char
type GuessedLetter = Guessed Letter | Unguessed
In my View module, I have a function for displaying a letter:
guessToChar : GuessedLetter -> Char
guessToChar guess =
case guess of
Guessed l -> l
Unguessed -> '_'
But when I try compiling these files, I get the following error:
## ERRORS in src/Views.elm #####################################################
-- NAMING ERROR -------------------------------------------------- src/Views.elm
Cannot find pattern `Guessed`
21| Guessed l -> l
^^^^^^^^^
-- NAMING ERROR -------------------------------------------------- src/Views.elm
Cannot find pattern `Unguessed`
22| Unguessed -> '_'
^^^^^^^^^
Detected errors in 1 module.
I thought "Maybe I should export the tags as well as the type?", but neither adding the tags to the module exports nor attempting to fully-qualify the tags (GuessedLetter.Guessed) has resolved the issue.
How do I fix this function?
As I suspected, if you want to use the tags outside the module, you have to export them too. (I just wan't sure how).
To do that, add the tags in a comma-separated list inside parentheses.
From the source code for Maybe (a type that 'worked' the way I wanted mine to):
module Maybe exposing
( Maybe(Just,Nothing)
, andThen
, map, map2, map3, map4, map5
, withDefault
, oneOf
)
Or in my case:
module Game exposing (Letter, GuessedLetter(Guessed, Unguessed))
On the importing side, you can then choose to fully-qualify the tags (with the module, not the type):
import Game exposing GuessedLetter
{- ... -}
guessToChar : GuessedLetter -> Char
guessToChar guess =
case guess of
Game.Guessed l -> l
Game.Unguessed -> '_'
or expose the tags too:
import Game exposing GuessedLetter(Guessed, Unguessed)
{- ... -}
guessToChar : GuessedLetter -> Char
guessToChar guess =
case guess of
Guessed l -> l
Unguessed -> '_'

(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 "")