What is the difference between using a unit and not using one? - f#

I am curious as to what is the major significance, if any in regards to taking a unit or not in code similar to below. What are the advantages or disadvantages. To my current understanding, taking a unit will implement a function that returns a value while not taking one just simply represents the value. Looking for some clarity here.
code without Unit:
let consumerKey =
// retrieve keys
query{
for row in db.Keys do
select {
consumerKey = row.ConsumerKey;
consumerSecret = row.ConsumerSecret
}
exactlyOneOrDefault
}
code with Unit:
let consumerKey() =
// retrieve keys
query{
for row in db.Keys do
select {
consumerKey = row.ConsumerKey;
consumerSecret = row.ConsumerSecret
}
exactlyOneOrDefault
}

The first block of code binds a value of type query<_> to identifier consumerKey while the second binds a value of type () -> query<_> to identifier consumerKey. The second is a function which when given unit will return a value of type query<_>.
In this example, the difference between the two are explicitly captured by their signatures. In other words, the first can be obtained from the second by invoking the function value with (). In terms of runtime, the second will always return a new underlying object instance, while the first one is fixed.
In cases where the evaluation causes side effects, the same would not hold. For example in thw following:
let value1 = Guid.NewGuid()
let value2 () = Guid.NewGuid()
A value1 cannot be obtained via value2 because a different value would be returned for each invocation.

Related

How to Serialize an Object to Json in F# excluding defaults and Keeping Enum Names

I thought this would have been easy but I am having issues ticking all the boxes that I need in this.
I need to
Serialize an object to Json
Ignore any properties not set
Use the ENum names instead of integer values
I have generated all the models for this using the Open API Generator based on a .yaml spec.
My first attempt was to get a bit of code from what looks like an old serializer
let json<'t> (myObj:'t) =
use ms = new MemoryStream()
let serialiser: DataContractJsonSerializer = new DataContractJsonSerializer(typeof<'t>)
let settings: DataContractJsonSerializerSettings = new DataContractJsonSerializerSettings()
(new DataContractJsonSerializer(typeof<'t>)).WriteObject(ms, myObj)
Encoding.Default.GetString(ms.ToArray())
This function actually does everything fine - except it copiess the enum numbers instead of names and I can't see an option to make this happpen.
My other attempt is using System.Text.Json.JsonSerializer:
let options
= new JsonSerializerOptions(
)
options.DefaultIgnoreCondition <- JsonIgnoreCondition.WhenWritingDefault
options.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase))
let jsonString:string = JsonSerializer.Serialize(shipmentRequest, options)
I have tried a few different things ( including excluding the Enum converter ) and I always get the following error.
Unable to cast object of type 'System.Int32' to type
'System.Nullable`1[Zimpla.Model.ExpressPackageReference+TypeCodeEnum]'
The specific Object ( roughly ) that it is having an issue with is:
[DataContract(Name = "ExpressPackageReference")]
public partial class ExpressPackageReference : IEquatable<ExpressPackageReference>, IValidatableObject
{
......etc
[DataMember(Name = "typeCode", EmitDefaultValue = false)]
public TypeCodeEnum? typeCode
{
get{ return _typeCode;}
set
{
_typeCode = value;
_flagtypeCode = true;
}
}
This particular property is not even set so it should be skipping over it theoretically. It is possible that I am not generating the object correctly
Without understanding all the details here, I think you are asking how you can serialize an object to json while omitting all properties that are null using System.Text.Json.
To accomplish that you have to set the following option:
options.IgnoreNullValues <- true
Here are the docs for this option:
https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonserializeroptions.ignorenullvalues?view=net-5.0#System_Text_Json_JsonSerializerOptions_IgnoreNullValues

Airtable Scripting block - Batch copy a field to another field in same table (10,000 records)

I'm trying to copy one field to another field in the same table with 10,000 + records, in batches of 50 using the Scripting App.
What am I doing wrong in this code block? It only copies the first record. If I remove the await, it'll copy 15 records then stop.
let table = base.getTable('Merchants');
let view = table.getView('Grid view');
let query = await view.selectRecordsAsync();
let records = query.records;
updateLotsOfRecords(records);
async function updateLotsOfRecords(records) {
let i = 0;
while (i < records.length) {
const recordBatch = records.slice(i, i + 50);
for (let record of recordBatch) {
let sourceValue = record.getCellValue('Merchant');
await table.updateRecordAsync(record, { 'LogoBase64': sourceValue });
}
i += 50;
}
}
you should use updateRecordsAsync function, not updateRecordAsync
When using single update function in loop, there is no sense to divide it into batches.
You exceed some limit of calls per second, that's why it stops.
For multiple updates, you need to use updateRecordsAsync, like this
while (recordsToWrite.length > 0) {
await updates.updateRecordsAsync(recordsToWrite.slice(0, 50));
recordsToWrite = recordsToWrite.slice(50);
}
Data that you should pass to it, more complex. I learned JS for 3 months and still have difficulties understandins all these "arrays of arrays of objects, passed via object's property". But that's the key to unerstand JS.
It's quite hard to leave basic/pascal habits, with plenty of inserted FOR loops, and GOTO sometimes))
I think, you already found the answer for 2 months, so my answer may be useless, but when i write it here, maybe i understand it better for myself. And help to some beginners also.
For single write, you pass (record, Object), where object is {field:'Value}
For multiple, you should pass
Array of Objects, where
Object is {id:recordID, fields:{object2}} , where
object2 is array of obj3 [ {obj3},{obj3}, {obj3} ], where
obj3 is a { 'Name or ID of field': fieldvalue }
you script might be:
let query = await view.selectRecordsAsync();
let updates=query.records.map(rec=>{
Map method can be applied for arrays, and 'query.records' is array of records. Here
'rec' is loop variable inside this "arrowfunction"
now let's create obj3 , in our case { 'Name or ID of field': fieldvalue }
{'LogoBase64':rec.getCellValue('Merchant')}
wrap it into fields property
fields:{'LogoBase64':rec.getCellValue('Merchant')}
and add record id
wrapping as Object.
To avoid complex string with linebreaks, and to make object creation easier, we can do it with function:
{rec.id, fields:{'LogoBase64':rec.getCellValue('Merchant')}}
fuction myObj(rec){return {rec.id, fields:{'LogoBase64':rec.getCellValue('Merchant')}}
map(rec=>myObj(rec)) - can be written as map(myObj)
we need array of objects, and map method gets first array, doing something with each element and return other array, of results. like we need.
and now finally we get
let table = base.getTable('Merchants');
let view = table.getView('Grid view');
let query = await view.selectRecordsAsync();
function myObj(rec){return {'id':rec.id,'fields':{'Logobase64':rec.getCellValue('Merchant')}}};
let updates=query.records.map(myObj);
while (updates.length > 0) {
await table.updateRecordsAsync(updates.slice(0, 50));
updates = updates.slice(50); }

Why is return type of this expression calculated to return type unit-> int instead of int

I am new to F# and am writing a function to convert a dateTime value to unix timestamp in seconds.
Below is my implementation of such a function (just using builtin function and wrapping it for learning).
let DateTimeToUnix x =
let result = DateTimeOffset(x).ToUnixTimeSeconds
result
Expected return type is: DateTime -> int64
Actual return type is: DateTime-> (unit->int64)
I tried to find similar questions and the closest i found was something like this (F# - The type int is not compatible with type unit)
but unfortunately i don't understand how it is applicable in this case since the return type of the function (ToUnixTimeSeconds) used is int64 and not (unit->int64).
It would be great if someone can point to where to learn about this or can explain the behavior. Thanks a lot for your time.
ToUnixTimeSeconds is a method, not a property. In F# methods are modeled as functions. Parameterless methods are modeled as functions with a single unit-typed parameter. So the type of foo.ToUnixTimeSeconds would be unit -> int64, just like the compiler is telling you.
To actually call that function and obtain a result from it, give it a parameter of the type that it expects - i.e. unit:
let DateTimeToUnix x =
let result = DateTimeOffset(x).ToUnixTimeSeconds ()
result
As a side note, you don't really have to name the intermediate value result:
let DateTimeToUnix x =
DateTimeOffset(x).ToUnixTimeSeconds ()
You have to invoke ToUnixTimeSeconds before returning it in order to get the desired return type:
let DateTimeToUnix x =
let result = DateTimeOffset(x).ToUnixTimeSeconds() // invoke method: ()
result

Can't understand the logic of F# mutable variable inside function body

I'm learning F# and get stuck with the concept of mutable keyword.
Please see the below example:
let count =
let mutable a = 1
fun () -> a <- a + 1; a
val count: unit -> int
Which increases by 1 every time it's called with (). But next code does not:
let count =
let mutable a = 1
a <- a + 1
a
val count: int
Which is always 2.
In the book I'm studying with, it says with the first example, "The initialization of mutable value a is done only once, when the function has called first time."
When I started learning FP with haskell, the way it handled side effects like this totally burnt my brain, but F# mutable is destroying my brain again, with a different way. What's the difference between above two snippets? And, what's the true meaning and condition of above sentence, about the initialization of mutable value?
Your second example
let count =
let mutable a = 1
a <- a + 1
a
Defines a mutable variable initialised to 1, then assigns a new value (a + 1) to it using the <- operator before returning the updated value on the last line. Since a has type int and this is returned from the function the return type of the function is also int.
The first example
let count =
let mutable a = 1
fun () -> a <- a + 1; a
also declares an int a initialised to 1. However instead of returning it directly it returns a function which closes over a. Each time this function is called, a is incremented and the updated value returned. It could be equivalently written as:
let count =
let mutable a = 1
let update () =
a <- a + 1
a
update
fun () -> ... defines a lambda expression. This version returns a 1-argument function reflected in the different return type of unit -> int.
The first example of count initializes a mutable variable, and returns a closure around this variable. Every time you call that closure, the variable is increased, and its new value returned.
The second example of count is just an initialization block that sets the variable, increases it once, and returns its value. Referring to count again only returns the already computed value again.

Can I make a record more flexible?

Can somebody give me an example of how to make inserting data into an F# record more flexible?
I often see examples using records like this:
type Employee = {mutable name:string; mutable id:string}
let data =
[{name = "Thomas";id = "000"};
{name = "Johny";id = "001"};
{name = "Lucky";id = "002"};
{name = "Don";id = "003"}
]
Can't we start with no data at all and insert the data into the record later?
(What I mean is without declaration of the value of the data like in the example, so for example: the program is running and asking us to insert the data)
Can we doing something like this with record?
If you're talking about specifying values of a record as they become available, then you need to make fields of the record option so that you can represent the fact that value is missing. I'll use immutable records, because this is more common in functional style:
type Employee = { Name:option<string>; ID:option<string> }
Now you can create a record with only ID and add name when the user enters it:
let empty = { Name = None; ID = Some 123 }
let name = // read name from user
let full = { empty with Name = name }
If you're talking about adding items to a list as they become available, then you have several options. The direct one is to write a recursive function that repeatedly reads record and builds a list:
let rec readData i records =
let name = // read name from user
if name <> "" then
// Create new record and add it to our list
let itm = { Name = name; ID = string i }
readData (i + 1) (itm::records)
else
// Return records that we collected so far in the right order
records |> List.rev
Alternatively, you can also use sequence expressions (see for example free Chapter 12 (PDF) of Real-World Functional Programming). If you user interaction involves waiting for events (e.g. mouse click), then you can still use this style, but you'd need to wrap everything in asynchronous workflow and use Async.AwaitEvent.
Are you saw you often saw an example like that?
I'd say that it is not very idiomatic in F# to use mutable records.
Immutability is a rather large subject
to explain in one answer here, but
briefly: immutability means that the
objects you create never change:
they stay the way they were at
creation. In the immutable world, when
you want to 'change' something, you
create a new one, and throw away the
old one.
Anyway, if I understand your question correctly, you are actually talking about mutating data, not the record. So, you could have:
let data = []
let data = {name = "Thomas";id = "000"} :: data
let data = {{name = "Johny";id = "001"} :: data
But in this case, you aren't really 'changing' data, you are just creating a new list each time and pointing data at it.

Resources