Applying a function on an F# array - arrays

type Sizes =
| Big
| Medium
| Small
;;
//defines cup/can/bottle with size
type Containment =
| CupDrink of s:Sizes
| CannedDrink of s:Sizes
| BottledDrink of s:Sizes
;;
// defines record for each type for drink
type Coffee = {DrinkName : string; price: double }
type Soda = {DrinkName : string; price: double }
type Brew = {DrinkName : string; price: double }
// union for type of drink
type liquid =
| Coffee of c:Coffee
| Cola of s:Soda
| Beer of b:Brew
;;
let Guiness = Beer {DrinkName = "Guiness"; price = 0.15}
let CocaCola = Cola {DrinkName = "Cola"; price = 0.15}
let smallCup = CupDrink Small // it could be just containment | size
let bigBottle= BottledDrink Big
let findPricePrML(dr:liquid) =
let price = 0.0
match dr with
|Beer(b=h)-> h.price
|Cola(s=h) ->h.price
|Coffee(c=h) -> h.price
|_-> failwith "not found"
// returns size in ML fro each size available // asuming that small bottle , can and cup have same size,
//if not another kind of program can be made but it's not part of the assingment
let find size =
match size with
|Big -> 250.00
|Medium -> 125.00
|Small -> 75.00
let grandTotal (dr:liquid ,cont:Containment) = function
(*let temp = {dra=dr;conta = cont} //supossed to search on menu list if such item exists (can't figure the syntax)
if List.contains temp menuList then *)
|CupDrink (s=z) -> findPricePrML dr * find z
|BottledDrink (s=z) -> findPricePrML dr * find z
|CannedDrink (s=z) -> findPricePrML dr * find z
|_-> failwith "not found"
(* else failwith "no such item exists"*)
;;
let source = [|(CocaCola, bigBottle); (CocaCola, smallCup); (Tuborg, smallCup)|]
let Test =
Async.Parallel [ async { return Array.map grandTotal source } ]
|> Async.RunSynchronously
Hello, I'm trying to learn basics of CPU bound parallel programming in F#. Here I have a function that calculates drink prices. And all i want is to apply another function(which multiplies the result with a certain number) to the results i get from the parallel calculation but I keep getting type mismatch errors. In my solution the result i get is a jagged array. Unfortunately i couldn't figure out how to get the results just as an array too.

I think that the first issue with your code is that your grandTotal function takes two arguments:
let grandTotal (dr:liquid, cont:Containment) = function
| ...
This means that you have to call it with something like grandTotal (CocaCola, bigBottle) drinkKind. However, in your code that tries to call this, you use:
Array.map grandTotal source
This calls grandTotal with only a single argument - an item from the source list, so you get back a function rather than a price. You probably need something like:
Array.map (fun drink -> grandTotal drink kind) source
The second issue is that you are not really parallelising anything. The way you use async, you are just creating a single computation and then running that on a background thread. You could do something like:
let test =
[ for a in source -> async { return grandTotal a kind } ]
|> Async.Parallel
|> Async.RunSynchronously
However, a more efficient and simpler approach is to use Array.Parallel.map:
Array.Parallel.map (fun drink -> grandTotal drink kind) source
To answer your question about calling another function - this is impossible without seeing a more complete code sample that we can run.

Related

map reduce sum item weights in a string

I have a string like the following:
s = "eggs 103.24,eggs 345.22,milk 231.25,widgets 123.11,milk 14.2"
such that a pair of item and its corresponding weights is separated by a comma, and the item name and its weight is by a space. I want to get the sum of the weights for each item:
//scala.collection.immutable.Map[String,Double] = Map(eggs -> 448.46, milk -> 245.45, widgets -> 123.11)
I have done the following but got stuck on the steps of separating out the item and its weight:
s.split(",").map(w=>(w,1)).sortWith(_._1 < _._1)
//Array[(String, Int)] = Array((eggs 345.22,1), (milk 14.2,1), (milk 231.25,1), (widgets 103.24,1), (widgets 123.11,1))
I think to proceed, for each element in the array I need to separate out the item name and weight separated by space, but when I tried the following I got quite confused:
s.split(",").map(w=>(w,1)).sortWith(_._1 < _._1).map(w => w._1.split(" ") )
//Array[Array[String]] = Array(Array(eggs, 345.22), Array(milk, 14.2), Array(milk, 231.25), Array(widgets, 103.24), Array(widgets, 123.11))
I am not sure what the next steps should be to proceed the calculations.
If you guaranteed to have the string in this format (so no exceptions and edge cases handling) you can do something like that:
val s = "eggs 103.24,eggs 345.22,milk 231.25,widgets 123.11,milk 14.2"
val result = s
.split(",") // array of strings like "eggs 103.24"
.map(_.split(" ")) // sequence of arrays like ["egg", "103.24"]
.map { case Array(x, y) => (x, y.toFloat)} // convert to tuples (key, number)
.groupBy(_._1) // group by key
.map(t => (t._1, t._2.map(_._2).sum)) // process groups, results in Map(eggs -> 448.46, ...)
Similar to what #GuruStron proposed, but handling possible errors (by just ignoring any kind of malformed data).
Also this one requires Scala 2.13+, older versions won't work.
def mapReduce(data: String): Map[String, Double] =
data
.split(',')
.iterator
.map(_.split(' '))
.collect {
case Array(key, value) =>
key.trim.toLowerCase -> value.toDoubleOption.getOrElse(default = 0)
}.toList
.groupMapReduce(_._1)(_._2)(_ + _)

Create a list of custom type in F# and create two sequences of that list

I have created my own type in F# called Accounts and I have then created objects for each account.
type Account() =
let AccountNumber = ""
let mutable Balance:float = 0.0
Every account has two fields, AccountNumber (string) and Balance (float).
I have then created an object for every account that holds the AccountName and the Balance.
let acc1 = new Account()
acc1.Insert("John",10.0)
let acc2 = new Account()
acc2.Insert("Mike",50.0)
How do I create a list that holds each account (object)? I have tried the following:
let AccountList : Account list = [acc1; acc2 ; acc3; acc4 ; acc5; acc6]
let AccountList : Account obj list = [acc1; acc2 ; acc3; acc4 ; acc5; acc6]
I cannot solve the problem using the above method because I have to create two sequences from the list:
Sequence 1: All accounts with a balance greater or equal to zero and less than 50
Sequence 2: All accounts with a balance above 50
How do I create a list of my custom type in F# and how do I create two sequences of that list?
It is not clear what exactly are you struggling with. However, the following simple example should illustrate most of the key ideas that you probably need to use. First, here is a small version of your Account class (note that I would normally use an immutable record, but I kept it the way you did it):
type Account(balance:float) =
let mutable balance = balance
member x.Balance = balance
member x.Add(difference) =
balance <- balance + difference
I do not see what issue you have with creating the list. The following works just fine:
let acc1 = Account(100.0)
let acc2 = Account(10.0)
let accountList = [acc1; acc2]
Now, to answer the question about finding accounts with balance over 50, you can use the List.filter function to create a new filtered list:
let above50 =
accountList |> List.filter (fun acc ->
acc.Balance > 50.0)
EDIT If you wanted to use a record instead, then you would define the type as:
type Account = { Balance : float }
And create a value using:
let acc1 = { Balance = 100.0 }
So I created this answer for the other one but I was waiting on the comment to see if I would answer. And the homework like aspect of this :)
So if you have criteria that bucket an account and want to do that in a single pass, you might want to look at groupBy. Here I use a boolean because there are only 2 possibilities but numbers or a discriminated union are good candidates.
open System
type Account(accountNumber:string, startingBalance:Int64) =
let mutable balance = startingBalance
member _.Balance = balance
member _.Deposit amount = balance <- balance + amount
member _.Withdraw amount = balance <- balance - amount
override _.ToString() = accountNumber
let allAccounts = [Account("ABC1", 10L); Account("ABC2", 50L)]
let grouped = allAccounts |> List.groupBy (fun a -> a.Balance >= 50L) |> Map.ofList
let under50 = grouped |> Map.tryFind false |> Option.defaultValue []
let overIncl50 = grouped |> Map.tryFind true |> Option.defaultValue []
printfn "Under: %A" under50
printfn "Over: %A" overIncl50

type tetris - stuck mixing monadic and pure code

I'm trying to implement bits and pieces of vulkan-tutorial in haskell.
For now im stuck trying to translate this code from c:
for (const char* layerName : validationLayers) {
bool layerFound = false;
for (const auto& layerProperties : availableLayers) {
if (strcmp(layerName, layerProperties.layerName) == 0) {
layerFound = true;
break;
}
}
if (!layerFound) {
return false;
}
}
return true;
So far i got to this point:
-- This has type (Int -> Text) -> Bool
let partOne = all (`elem` requiredValidationLayers) . flip map [0 .. realCount-1]
-- This has type Int -> IO Text
let partTwo i = do
let layerProperty = advancePtr layerProperties i
myField_ <- readStringField #"layerName" layerProperty
pure $ toS myField_ :: IO Text
I'm feeling that i have all the pieces here, but also that i might be going in a completely wrong direction.
How do i put this stuff together?
thanks
PS: ok, i just noticed that the set inclusion check is likely reversed - doesn't matter, lets for the sake of the question pretend that it's actually fine
thanks all commenters, i think i got it now :)
this is how it looks like (inside a do block of IO () ):
supportedLayers <- for [0 .. realCount-1] $ \i -> do
let layerProperty = advancePtr layerProperties i
myField_ <- readStringField #"layerName" layerProperty
pure $ toS myField_ :: IO Text
return $ requiredValidationLayers `includes` supportedLayers
where
includes :: Eq a => [a] -> [a] -> Bool
includes a b = all (`elem` b) a
I'm going to start with some assumptions:
You have a type data Layer = ...
You have a type alias type Name = String
You have some function layerName :: Layer -> Name
I'm going to walk through the definition of the pure function, not because it's terribly important, but because it uses a technique for moving from pure to impure (i.e., IO-dependent) code.
Does a given layer have a given name?
First, you have the base operation
strcmp(layerName, layerProperties.layerName) == 0
This is a simple Haskell function that takes a Name and a Layer and returns True if the layer has the given name.
hasName :: Name -> Layer -> Bool
hasName name layer = name == layerName layer
Does one of several layers have any one of several names?
But we don't have a single name or layer; we have lists of each. We can easily handle this by using the Applicative instance for lists to model nondeterminism.
import Control.Applicative
foo :: [Name] -> [Layer] -> [Bool]
foo = liftA2 hasName
I won't bother given this function a good name, because we won't need one.
Now, we can get a list of the result of comparing every name to every layer, but we don't care about the individual results: we just want one value that says if we found a match or not. For this, we'll use or :: [Bool] -> Bool.
findMatch :: [Name] -> [Layer] -> Bool
findMatch names layers = or (foo names layers)
foo is simple enough that we'll just inline its definition, so that we don't need to come up with a better name:
findMatch :: [Name] -> [Layer] -> Bool
findMatch names layers = or (liftA2 hasName names layers)
Handling IO
Now, we've been assuming that we already have our lists of names and layers as pure values. But what if we don't? What if we only have lists read in from a file or somewhere else, so that we have IO [Name] and/or IO [Layer]? The solution is to use liftA2 again, but instead of using the list instance of Applicative, we'll use the IO instance.
ionames :: IO [Name]
ionames = ...
iolayers :: IO [Layer]
iolayers = ...
result :: IO Bool
result = liftA2 findMatch ionames iolayers

ReasonML binding function with config having fixed string values

Lets say, that I have this function in Javascript which can generate string based on proper configuration:
function func(config) {
// ...
}
also, let's assume, that the config variable has structure as below (all of these can be not given to function call):
{
"color": string, // can be: "blue", "red", "green"
"number": int, // can be: any number
"other": string, // can be: "x", "y"
}
How to create proper binding for this? I'm stuck with:
[#bs.deriving abstract]
type options = {
[#bs.optional]
color: [#bs.string] [ | `blue | `red | `green ]
[#bs.optional]
number: int,
[#bs.optional]
other: [#bs.string] [ | `x | `y ]
}
[#bs.module]
external func: options => string = "func";
But it does not work when trying to use like this:
let config = MyModule.config(
~color=`blue,
~number=123,
~other=`x
);
let value = MyModule.func(config);
The color and other values are integers, not strings.
This is a case of a JavaScript idiom for named parameters (objects with optional fields), needing to be adapted to the OCaml/ReasonML idiom (functions with actual labelled parameters). You would do this in three steps. Step 1, as Glenn showed, define an external for the config:
type config;
[#bs.obj] external config: (
~color:[#bs.string] [`blue | `red | `green]=?,
~number:int=?,
~other:[#bs.string] [`x | `y]=?,
unit,
) => config = "";
Step 2, bind to the JavaScript function using the JavaScript style of the config object:
[#bs.val] external func: config => string = "";
Step 3, wrap the JavaScript function binding in an OCaml-idiomatic function with labelled parameters:
let func(~color=?, ~number=?, ~other=?, ()) = ()
|> config(~color?, ~number?, ~other?)
|> func;
You can use it like this:
let result = func(~color=`blue, ());
The #bs attributes are often poorly thought out hacks that you shouldn't expect to work well with other attributes, or really with anything other than exactly what the documentation explains or shows examples of. However, if an attribute is used where it is not intended you'll usually at least get a warning about the attribute being unused, which your code does.
#bs.string in particular only works on types at the outermost level of externals, i.e. on types whose values will be passed directly to the external function. There is also a way to create JavaScript objects using external functions which also happens to use less magic and give you much more control over the API. As far as I'm aware, the only downside compared to #bs.deriving is that you can't override field names using something like #bs.as. They have to be valid OCaml identifiers.
Here's your example implemented using an external function annotated with #bs.obj:
type options;
[#bs.obj] external options : (
~color:[#bs.string] [`blue | `red | `green]=?,
~number:int=?,
~other:[#bs.string] [`x | `y]=?,
unit
) => options = "";
To use it you call it exactly as with #bs.deriving:
let config = options(~color=`blue,~number=123, ~other=`x, ());
But even with this I've encountered edge cases where integer values are passed in instead of strings. For this reason I tend to avoid the polymorphic variant attributes altogether and instead use ordinary variants along with conversion functions. This has the added benefit of being more idiomatic, blending in better and being more interoperable with non-BuckleScript code.
Here's what your example might look like using this approach:
type color = Blue | Red | Green;
let colorToString = fun
| Blue => "blue"
| Red => "red"
| Green => "green";
type other = X | Y;
let otherToString = fun
| X => "x"
| Y => "y";
[#bs.obj] external options : (
~color:string=?,
~number:int=?,
~other:string=?,
unit
) => options = "";
[#bs.module] external func: options => string = "func";
let func = (~color=?, ~number=?, ~other=?, ()) =>
func(options(
~color = ?Belt.Option.map(color, colorToString),
~number?,
~other = ?Belt.Option.map(other, otherToString),
()));
let config = func(~color=Blue,~number=123, ~other=X, ());
This is because in reality, those values are variants, instead of trying to make it exactly like JavaScript, I would rather try something more idiomatic to Reason:
type color = Blue | Green | Red;
type coords = X | Y;
type config = {
color,
coords,
number: int
};
let func = (config: config) => "something"
And then inside your function actually return strings (if that is what you really need) by pattern matching on the correct values provided to config.
See the working code here.
Hope it helps!

Drawing in a Windows Form in F#

I'm attempting to draw in a non-customized (I mean, simply creating an instance of the default form class, not an instance of a deriving class I can create) System.Windows.Forms.Form in F#.
I had created a custom form, but I didn't need nor want a new complex structure like that, so I removed it, and it simplified the code a lot; so much, that it stopped to show an image.
The problem must be in the function I created to draw, that is in another F# project. I've created it (function conect) to connect points in the order they are provided, unlike System.Drawing.Graphics.DrawLines, that draws lines between the points in some other order why haven't noticed yet (maybe right to left, top to bottom, as the points are represented).
Programa.fs relevant code snippet:
let pen = new Pen(brush = Brushes.Black, width = 1.0f)
let original =
([|new PointF(50.0f, 50.0f); new PointF(100.0f, 50.0f)|])
use form1 = new Form(Width = 400, Height = 400, Text = "Fractais (Teste - Windows Forms)")
form1.Paint.Add(
fun e -> // (1)
original
|> List.ofArray
|> Base.applyFractal 1uy Base.fractalFunc1
|> Base.conect e.Graphics pen)
If in the lambda expression instead of what's written there was e.Graphics.DrawLines(pen, original), it would draw a simple line between the points in the list.
Here's the troublemaker method, in Base.fs, across the solution:
let conect (gr:Graphics) (pen:Pen) (points:PointF list) =
let rec usefulFunc (gr:Graphics) (pen:Pen) (points:PointF list) prevPoint =
match points with
| [] -> ()
| point :: remainings ->
gr.DrawLine (pen, prevPoint, point)
usefulFunc gr caneta remainings.Tail remainings.Head
usefulFunc gr pen points.Tail points.Head
And the called (from the form initialization snippet) and relevant methods' signatures, in Base.fsi (I could give you all of the full methods' implementation, but it would take a lot of space, and this is probably for you already becoming a long question to read):
val fractalFunc1 : points:PointF list -> PointF list
val applyFractal : stepNumber:byte -> fractalFunc:(PointF list -> PointF list) -> points:PointF list -> PointF list
val conect : gr:Graphics -> pen:Pen -> points:PointF list -> unit
For this specific problem, my search results were none. I'd like to know how can I make the function conect work.
Thanks in advance.
You have one error in conectar.
fUtil gr caneta resto.Tail resto.Head
Should be
fUtil gr caneta resto ponto
You're already matching the head and tail inside of the match statement.
The following code draws a line for me. I didn't have to modify much.
open System.Drawing
open System.Windows.Forms
let caneta = new Pen(brush = Brushes.Black, width = 1.0f)
let original =
([|new PointF(50.0f, 50.0f); new PointF(100.0f, 50.0f)|])
let form1 = new Form(Width = 400, Height = 400, Text = "Fractais (Teste - Windows Forms)")
let conectar (gr:Graphics) (caneta:Pen) (pontos:PointF list) =
let rec fUtil (gr:Graphics) (caneta:Pen) (pontos:PointF list) pontoAnt =
match pontos with
| [] -> ()
| ponto :: resto ->
gr.DrawLine (caneta, pontoAnt, ponto)
fUtil gr caneta resto ponto
fUtil gr caneta pontos.Tail pontos.Head
form1.Paint.Add(
fun e -> // (1)
original
|> List.ofArray
//|> aplicFractal 1uy Base.funcFractal1
|> conectar e.Graphics caneta)
form1.Show()
Application.Run(form1)

Resources