F# Make - Restore certain Nuget packages with PreRelease option - f#-fake

In order to specify additional internal company Nuget feeds, I am currently using RestorePackages like this:
let RestorePackages() =
!! "./**/packages.config"
|> Seq.iter (RestorePackage(fun p -> {p with Sources = "http://internal.example.com/nuget" :: p.Sources}))
Which works great. How can I get the script to restore certain packages with the IncludePreRelease option set?
I have tried matching on the package like this:
let RestorePackages() =
!! "./**/packages.config"
|> Seq.iter (fun item ->
match item with
| "Example" -> RestorePackageId(fun p -> {p with IncludePreRelease = true}) "Example"
| item -> RestorePackage(fun p -> {p with Sources = "http://internal.example.com/nuget" :: p.Sources}))
But that doesn't work. The default match to call RestorePackage says "This expression was expected to have type unit but here has type string -> unit".

Looks like you're missing a string at the end of your last code line. I think you should pass item variable there.
let RestorePackages() =
!! "./**/packages.config"
|> Seq.iter (fun item ->
match item with
| "Example" -> RestorePackageId(fun p -> {p with IncludePreRelease = true}) "Example"
| item -> RestorePackage(fun p -> {p with Sources = "http://internal.example.com/nuget" :: p.Sources}) item)

Related

How to build a SelectList from a List and a (a -> Bool)?

I am using elm-spa-example model and I have a Session that contains a List Recipe as well as a Model that contains a recipeID
I'd like to build a SelectList that would select the recipe that has got the RecipeID in the list.
Ideally I would use something like:
SelectList.selectFromList : (a -> Bool) -> List a -> SelectList a
I my case I would do:
SelectList.selectFromList (\recipe -> recipe.id == recipeID) session.recipes
I did something like that:
selectFromList : (a -> Bool) -> List a -> Maybe (SelectList a)
selectFromList isSelectable list =
case list of
first :: rest ->
SelectList.fromLists [] first rest
|> SelectList.select isSelectable
|> Just
[] ->
Nothing
I also added:
prev : SelectList a -> Maybe a
prev list =
SelectList.before list
|> List.reverse
|> List.head
next : SelectList a -> Maybe a
next list =
SelectList.after list
|> List.head
I put together this quick ellie that illustrates what I think are the steps needed to achieve what you want. It's certainly not optimized or even idiomatic.
https://ellie-app.com/4TJVgSCwXa1/0
firstPartialList = takeWhile condition myList
selected = Maybe.withDefault "" (getAt (length firstPartialList) myList)
secondPartialList = drop ((length firstPartialList) + 1) myList
mySelectList = SelectList.fromLists firstPartialList selected secondPartialList
condition = (\item -> item /= otherItem)
myList = ["a", "b", "c", "d"]
otherItem = "b"
SelectList doesn't expose selectFromList are you sure the link is right?

Best way to get next element of a List in Elm

I am currently trying to figure out the best way of traversing a List.
What do I mean by traversing?
Example:
I have a List of Users:
userList : List User
userList =
[user, user, user, user]
and I have a currentUser, which must be a user out of the userList
So what I want to achieve is:
I want to have something like List.getNext which takes the userList and the current user and returns the next user in the list, relative to the currentUser
Here is my implementation. I think it is very complicated - so has anyone an idea how to do this in a better style?
traverseList : List a -> a -> Maybe (Maybe a)
traverseList list currentElement =
let
indexList =
List.indexedMap
(\index element ->
if element == currentElement then
index
else
-1
)
list
currentAsIndex =
let
mayBeIndex =
List.maximum indexList
in
case mayBeIndex of
Just index ->
index
Nothing ->
0
getWanted =
List.map
(\( id, element ) ->
if id == (currentAsIndex + 1) then
Just element
else
Nothing
)
(List.indexedMap (,) list)
|> List.filter
(\element ->
element /= Nothing
)
|> List.head
in
getWanted
Explanation:
My approach is to get the list, make an index list of the given list (looks like this [-1, -1, -1, 3, -1, -1])
Then I get the maximum of this list - as this gives me the position of the current user in a List.indexedMap.
Then I iterate the original as an List.indexedMap and figure out the next one (in our case No. 4) and return that element. Else I return nothing.
Then I filter this List of Nothings and just one user and extract the user from the list by using List.head.
The Result is a Maybe (Maybe user)... that is not so nice... or?
Thanks for any ideas to do something like this in a better functional way.
I really try to get better in functional programming..
Here is a pretty naive, recursive solution:
getWanted : List a -> a -> Maybe a
getWanted list currentElement =
let findNextInList l = case l of
[] -> Nothing
x :: [] -> if x == currentElement
then List.head list
else Nothing
x :: y :: rest -> if x == currentElement
then Just y
else findNextInList (y :: rest)
in
findNextInList list
The idea here is look at the first two elements of the list, and if the first is the current element, take the second. If not, try again with the tail of the list.
Corner cases must be handled (you can write at least 4 unit tests for this function):
current element not found at all
current element is the last in the list
the list might be empty
Maybe there is a more elegant solution, but recursion is a pretty common technique in functional programming, so I wanted to share this approach.
If you are willing to import list-extra you can use
import List.Extra as LE exposing ((!!))
getNext : a -> List a -> Maybe a
getNext item list =
list
|> LE.elemIndex item
|> Maybe.map ((+) 1)
|> Maybe.andThen ((!!) list)
If the found element is the last in the list it returns Nothing
Another possible solution:
getNext : List a -> a -> Maybe a
getNext list element =
list
|> List.drop 1
|> zip list
|> List.filter (\(current, next) -> current == element)
|> List.map (\(current, next) -> next)
|> List.head
zip : List a -> List b -> List (a,b)
zip = List.map2 (,)
We drop the first element of the list and then zip it with the original list to get a list of tuples. Each element of the tuple contains the current element and the next element. We then filter that list, take the 'next' element from the tuple and take the head of the final list.
I like farmio's library-based approach best, and is what I'll be using in future.
That said, for being new to elm and not looking over its libraries, my erstwhile approach has been as in the following: i.e. index the list, find index if any of searched-for item, get item at next index if any.
nextUser : List User -> User -> Maybe User
nextUser lst usr =
let
numberedUsers =
List.map2 (\idx u -> ( idx, u )) (List.range 1 (List.length lst)) lst
usrIdx =
List.filter (\( idx, u ) -> u.name == usr.name) numberedUsers
|> List.head
|> Maybe.map Tuple.first
|> Maybe.withDefault -1
in
List.filter (\( idx, u ) -> idx == usrIdx + 1) numberedUsers
|> List.head
|> Maybe.map Tuple.second
Another way with as much fiddlery would be to use folds.
Maybe instead of List just use Array, which provides index-based access.
There are some good answers to the concrete question. I'd like to suggest an alternative model, since this approach has some downsides:
You rely on checking equality of users. This limits the user type, e.g., there can't be functions in there.
Looking up a user in a list that doesn't guarantee that all users are different is fragile: If the list happens to end up as [user1, user2, user1, user3], the rotation will never reach user3.
Nothing guarantees that the current user is in the list, hence the Maybe in the return type of the other answers which is hard to deal with correctly.
Thus, let's assume your current model is
type alias Model =
{ currentUser : User
, users : [User]
}
and what you're asking for is
rotateUser : Model -> Model
rotateUser model =
let
nextUser = Maybe.withDefault
model.currentUser
(getNext model.users model.currentUser)
in
{ model | currentUser = nextUser }
getNext : List a -> a -> Maybe a
...
How about instead of implementing getNext, we change the model to make life easier:
type alias Model =
{ currentUser : User
, otherUsers : [User]
}
rotateUser : Model -> Model
rotateUser model =
case model.otherUsers of
[] -> model
(nextUser::rest) ->
{ model
| currentUser = nextUser
, otherUsers = rest ++ [model.currentUser]
}

Getting list element giving compilation error: "Arrows are reserved for cases and anonymous functions. Maybe you want > or >= instead?"

--define person type
type alias Person ={name: String, age: Int}
--created list of persons named people
people = [{name = "John", age = 41}, {name = "Nancy", age = 37}]
List item
names: List Person -> List String
names peeps = List.map(\peep -> peep.name) peeps
findPerson : String -> List Person -> Maybe Person
--using foldl to iterate list, here I am getting compile time error
findPerson name peeps = List.foldl(\peep memo -> case memo of Just _ ->
Nothing -> if peep.name == name then Just peep else Nothing ) Nothing peeps
main = text <| toString <| findPerson "John" people
Elm is whitespace-sensitive. The lines you flagged have invalid Elm code.
Your case statements should be in the form of:
case something of
Just val -> "we have a valid value: " ++ val
Nothing -> "we have nothing"
Furthermore, a foldl is probably not what you want for finding something in a list. You could get by with this implementation, which filters a list and takes the first element, if it exists.
findPerson : String -> List Person -> Maybe Person
findPerson name peeps =
List.filter (\peep -> peep.name == name) peeps
|> List.head

Using F# Fake SquirrelHelper to create Squirrel.Windows packages

Attempting to create a SquirrelPack target however it does not seem to be working for me using the docs:
// line 84
Target "CreateSquirrelPackage" (fun _ ->
SquirrelPack (fun p -> {p with WorkingDir = "./tmp"}) "./my.nuget"
)
// line 88
Output
build.fsx(86,49): error FS0001: This expression was expected to have type
string option
but here has type
string
Has anyone been able to get SquirrelPack working in F#Fake?
WorkingDir has type string option, but you're trying to make it just a string.
This should work:
Target "CreateSquirrelPackage" (fun _ ->
SquirrelPack (fun p -> {p with WorkingDir = Some "./tmp"}) "./my.nuget"
)

More FP-correct way to create an update sql query

I am working on access a database using F# and my initial attempt at creating a function to create the update query is flawed.
let BuildUserUpdateQuery (oldUser:UserType) (newUser:UserType) =
let buf = new System.Text.StringBuilder("UPDATE users SET ");
if (oldUser.FirstName.Equals(newUser.FirstName) = false) then buf.Append("SET first_name='").Append(newUser.FirstName).Append("'" ) |> ignore
if (oldUser.LastName.Equals(newUser.LastName) = false) then buf.Append("SET last_name='").Append(newUser.LastName).Append("'" ) |> ignore
if (oldUser.UserName.Equals(newUser.UserName) = false) then buf.Append("SET username='").Append(newUser.UserName).Append("'" ) |> ignore
buf.Append(" WHERE id=").Append(newUser.Id).ToString()
This doesn't properly put a , between any update parts after the first, for example:
UPDATE users SET first_name='Firstname', last_name='lastname' WHERE id=...
I could put in a mutable variable to keep track when the first part of the set clause is appended, but that seems wrong.
I could just create an list of tuples, where each tuple is oldtext, newtext, columnname, so that I could then loop through the list and build up the query, but it seems that I should be passing in a StringBuilder to a recursive function, returning back a boolean which is then passed as a parameter to the recursive function.
Does this seem to be the best approach, or is there a better one?
UPDATE:
Here is what I am using as my current solution, as I wanted to make it more generalized, so I just need to write an abstract class for my entities to derive from and they can use the same function. I chose to split up how I do the function so I can pass in how to create the SET part of the update so I can test with different ideas.
let BuildUserUpdateQuery3 (oldUser:UserType) (newUser:UserType) =
let properties = List.zip3 oldUser.ToSqlValuesList newUser.ToSqlValuesList oldUser.ToSqlColumnList
let init = false, new StringBuilder()
let anyChange, (formatted:StringBuilder) =
properties |> Seq.fold (fun (anyChange, sb) (oldVal, newVal, name) ->
match(oldVal=newVal) with
| true -> anyChange, sb
| _ ->
match(anyChange) with
| true -> true, sb.AppendFormat(",{0} = '{1}'", name, newVal)
| _ -> true, sb.AppendFormat("{0} = '{1}'", name, newVal)
) init
formatted.ToString()
let BuildUserUpdateQuery (oldUser:UserType) (newUser:UserType) (updatequery:UserType->UserType->String) =
let buf = StringBuilder("UPDATE users SET ");
buf.AppendFormat(" {0} WHERE id={1}", (updatequery oldUser newUser), newUser.Id)
let UpdateUser conn (oldUser:UserType) (newUser:UserType) =
let query = BuildUserUpdateQuery oldUser newUser BuildUserUpdateQuery3
execNonQuery conn (query.ToString())
Is this the tuple solution you had in mind?
let BuildUserUpdateQuery (oldUser:UserType) (newUser:UserType) =
let buf = StringBuilder("UPDATE users set ")
let properties =
[(oldUser.FirstName, newUser.FirstName, "first_name")
(oldUser.LastName, newUser.LastName, "last_name")
(oldUser.UserName, newUser.UserName, "username")]
|> Seq.map (fun (oldV, newV, field) ->
if oldV <> newV
then sprintf "%s='%s'" field newV
else null)
|> Seq.filter (fun p -> p <> null)
|> Seq.toArray
if properties.Length = 0
then None
else
bprintf buf "%s" (String.Join(", ", properties))
bprintf buf " where id=%d" newUser.Id
Some <| buf.ToString()
I don't see how the recursive solution could be simpler than this...
BTW I would strongly advise to use proper SQL parameters instead of just concatenating the values, you might become vulnerable to injection attacks...
Just for completeness, here is a version that does the same thing directly using the fold function. This can be done quite elegantly, because methods of StringBuilder return the StringBuilder (which allows you to chain them in C#). This can be also used nicely for folding.
Let's assume that we have the list of tuples from the solution by Mauricio:
let properties =
[ (oldUser.FirstName, newUser.FirstName, "first_name")
(oldUser.LastName, newUser.LastName, "last_name")
(oldUser.UserName, newUser.UserName, "username") ]
Now you can write the following code (it also returns a flag whether anything has changed):
let init = false, new StringBuilder()
let anyChange, formatted =
properties |> Seq.fold (fun (anyChange, sb) (oldVal, newVal, name) ->
if (oldVal = newVal) anyChange, sb
else true, sb.AppendFormat("{0} = '{1}'", name, newVal)) init
The state kept during folding has type bool * StringBuilder and we start with an initial value containing empty string builder and false. In each step, we either return the original state (if value is the same as previous) or a new state containing true and a new version of the StringBuilder returned by AppendFormat.
Using recursion explicitly would also work, but when you can use some built-in F# function, it is usually easier to use this approach. If you needed to process nested entities of each entity, you could use the Seq.collect function together with recursion to get a list of properties that you need to process using fold. Pseudo-code might look like this:
let rec processEntities list names =
// Pair matching entity with the name from the list of names
List.zip list names
|> List.collect (fun (entity, name) ->
// Current element containing old value, new value and property name
let current = (entity.OldValue, entity.NewValue, name)
// Recursively proces nested entitites
let nested = processEntities entity.Nested
current::nested)
This can be more elegantly written using sequence expressions:
let rec processEntities list =
seq { for entity, name in List.zip list names do
yield (entity.OldValue, entity.NewValue, name)
yield! processEntities entity.Nested }
Then you could simply call processEntities which returns a flat list of entities and process the entities using fold as in the first case.
I like both Mauricio's and Tomas's solutions, but perhaps this is more like what you originally envisioned?
let sqlFormat (value:'a) = //'
match box value with
| :? int | :? float -> value.ToString()
| _ -> sprintf "'%A'" value // this should actually use database specific escaping logic to make it safe
let appendToQuery getProp (sqlName:string) (oldEntity,newEntity,statements) =
let newStatements =
if (getProp oldEntity <> getProp newEntity) then (sprintf "%s=%s" sqlName (sqlFormat (getProp newEntity)))::statements
else statements
(oldEntity, newEntity, newStatements)
let createUserUpdate (oldUser:UserType) newUser =
let (_,_,statements) =
(oldUser,newUser,[])
|> appendToQuery (fun u -> u.FirstName) "first_name"
|> appendToQuery (fun u -> u.LastName) "last_name"
|> appendToQuery (fun u -> u.UserName) "username"
// ...
let statementArr = statements |> List.toArray
if (statementArr.Length > 0) then
let joinedStatements = System.String.Join(", ", statementArr)
Some(sprintf "UPDATE users SET %s WHERE ID=%i" joinedStatements newUser.ID)
else
None
If you have lots of properties to check, this may be a bit more concise. One benefit to this approach is that it works even if you're checking properties of multiple types, whereas the other approaches require all properties to have the same type (since they're stored in a list).