How do I pre-load a list of images in Fable F#? [closed] - fable-f#

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I'm fairly new to both F# and Fable. I have the following code in JavaScript to load up some images and then do stuff with them when they're all loaded:
async function start() {
async function loadImages(files) {
let promises = files.map(filename => {
return new Promise((resolve, reject) => {
const img = new Image();
img.src = filename;
img.onload = () => resolve(img);
})
});
return Promise.all(promises);
}
const images = await loadImages(imageFileNames);
// Do stuff with images
console.log('images loaded', images);
}
start();
How would I go about writing this in F# for use in Fable?
I'm using the Fable Simple Template (which I believe is Fable 1.x not the new version 2?)

This is what I've come up with, which does the job although I'm sure there's a nicer way:
let loadImages imageFileNames callback =
let mutable remaining : int = (imageFileNames |> List.length) - 1
let imagesWithNames =
imageFileNames
|> List.map (fun fileName ->
let img = Browser.document.createElement_img()
fileName,img
)
let images =
imagesWithNames
|> List.map (fun (_,img) -> img)
for (fileName, img) in imagesWithNames do
img.onload <- (fun _ ->
if remaining > 0 then
remaining <- remaining - 1
else
callback(images)
())
img.src <- fileName
()
// Use with a callback, e.g.
let imageFileNames = [ "grass.png" ; "hedge.png" ];
loadImages imageFileNames (fun images -> printfn "%A" images)
This was inspired/copied from this javascript version: https://stackoverflow.com/a/41170913

Related

Bookmarklet - Multiple lines of input

I am trying to create a simple bookmarklet that creates a little textbox that can be created, written in, and then closed.
Thank you ahead of time.
See a live example here
(() => {
const d = document.createElement('div')
d.style = "position:fixed;top:0px;left:0px;padding:5px;background-color:red;"
const e = document.createElement('textarea')
const b = document.createElement('button')
b.innerText = "Close"
b.onclick = () => {
document.body.removeChild(d)
}
d.appendChild(e)
d.appendChild(b)
document.body.appendChild(d)
})();

Group items from list and sort it [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I have a list with items:
Header1, Item1, Item2, Item3, Header2, Item4, Item5, Header3, Item6, Item7
Every single header has title.
How I can group that elements into Header + items, Header + items etc. and sort it alphabetically by header title?
I believe this problem isn't trivial to solve with functional-style transformations like group by, etc. Such operations are not that useful if we need to reference previous items in the collection.
I suggest using imperative style and good old loops:
fun Iterable<Base>.groupByHeader(): Map<Header, List<Item>> {
val iter = iterator()
if (! iter.hasNext()) {
return emptyMap()
}
var currHeader = requireNotNull(iter.next() as? Header)
var currItems = mutableListOf<Item>()
val result = sortedMapOf(compareBy(Header::title), currHeader to currItems)
iter.forEach { item ->
when (item) {
is Header -> {
currHeader = item
currItems = mutableListOf()
result[currHeader] = currItems
}
is Item -> currItems.add(item)
else -> throw IllegalArgumentException()
}
}
return result
}
If we really like functional style then reduce/fold is probably our best option. We can use fold() in a similar way as above, but we can also utilize runningFold() like this:
fun Iterable<Base>.groupByHeader(): Map<Header, List<Item>> {
return runningFold(Pair<Header?, Item?>(null, null)) { acc, item ->
when (item) {
is Header -> item to null
is Item -> acc.first to item
else -> throw IllegalArgumentException()
}
}.filter { it.first != null && it.second != null }
.groupByTo(sortedMapOf(compareBy(Header::title)), { it.first!! }, { it.second!! })
}
This is shorter, but probably harder to understand, much less performant and it ignores Item objects placed at the beginning - first solution throws an exception in such a case.

F# equivalent of C# async event handler in Xamarin iOS [duplicate]

How does one code an asynchronous WPF (or Windows Forms) event handler in F#? Specifically, is there any coding pattern that approximates C# 5's async and await?
Here is a complete C# WPF app:
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
class Program
{
static int IncrementSlowly(int previous)
{
Thread.Sleep(3000);
if (previous == 2) throw new Exception("Oops!");
return previous + 1;
}
static async void btn_Click(object sender, RoutedEventArgs e)
{
var btn = sender as Button;
btn.IsEnabled = false;
try
{
var prev = (int)btn.Content;
btn.Content = await Task.Run(() => IncrementSlowly(prev));
}
catch (Exception ex)
{
btn.Content = ex.Message;
}
finally
{
btn.IsEnabled = true;
}
}
[STAThread]
static void Main(string[] args)
{
var btn = new Button() { Content = 0 };
var win = new Window() { Content = btn };
btn.Click += btn_Click;
new Application().Run(win);
}
}
I am having trouble figuring out what the equivalent would be using F#. I have made several attempts using combinations of async workflows and Async methods. It just gets really messy real fast. I'm hoping there is an easy way that I'm just overlooking.
Here is my starting point, which locks up the UI at btn.Content <- incrementSlowly prev. What do I do next?
open System
open System.Threading
open System.Threading.Tasks
open System.Windows
open System.Windows.Controls
let incrementSlowly previous =
Thread.Sleep(3000)
if previous = 2 then failwith "Oops!"
previous + 1
let btn_Click (sender : obj) e =
let btn = sender :?> Button
btn.IsEnabled <- false
try
try
let prev = btn.Content :?> int
btn.Content <- incrementSlowly prev
with ex -> btn.Content <- ex.Message
finally
btn.IsEnabled <- true
[<EntryPoint>][<STAThread>]
let main _ =
let btn = new Button(Content = 0)
let win = new Window(Content = btn)
btn.Click.AddHandler(RoutedEventHandler(btn_Click))
Application().Run(win)
By the way, assume that incrementSlowly cannot be modified.
The first step is to make incrementSlowly asynchronous. This is actually synchronous in your C# code, which is probably not a good idea - in a realistic scenario, this could be communicating with network, so very often this can actually be asynchronous:
let incrementSlowly previous = async {
do! Async.Sleep(3000)
if previous = 2 then failwith "Oops!"
return previous + 1 }
Now, you can make the button click handler also asynchronous. We'll start it using Async.StartImmediate later to make sure that we can access UI elements, so we do not have to worry about dispatechers or UI threads for now:
let btn_Click (sender : obj) e = async {
let btn = sender :?> Button
btn.IsEnabled <- false
try
try
let prev = btn.Content :?> int
let! next = incrementSlowly prev
btn.Content <- next
with ex -> btn.Content <- ex.Message
finally
btn.IsEnabled <- true }
The final step is to change the event registration. Something like this should do the trick:
btn.Click.Add(RoutedEventHandler(fun sender e ->
btn_Click sender e |> Async.StartImmediate)
The key thing is Async.StartImmediate which starts the asynchronous workflow. When we call this on the UI thread, it ensures that all the actual work is done on the UI thread (unless you offload it explicitly to background) and so it is safe to access UI elements in your code.
Tomas correctly points out that if you can convert the slow method to be asynchronous, then let! and Async.StartImmedate work beautifully. That is preferred.
However, some slow methods do not have asynchronous counterparts. In that case, Tomas's suggestion of Async.AwaitTask works too. For completeness I mention another alternative, manually managing the marshalling with Async.SwitchToContext.
Async.AwaitTask a new Task
let btn_Click (sender : obj) e =
let btn = sender :?> Button
btn.IsEnabled <- false
async {
try
try
let prev = btn.Content :?> int
let! next = Task.Run(fun () -> incrementSlowly prev) |> Async.AwaitTask
btn.Content <- next
with ex -> btn.Content <- ex.Message
finally
btn.IsEnabled <- true
}
|> Async.StartImmediate
Manually manage thread context
let btn_Click (sender : obj) e =
let btn = sender :?> Button
btn.IsEnabled <- false
let prev = btn.Content :?> int
let uiContext = SynchronizationContext.Current
async {
try
try
let next = incrementSlowly prev
do! Async.SwitchToContext uiContext
btn.Content <- next
with ex ->
do! Async.SwitchToContext uiContext
btn.Content <- ex.Message
finally
btn.IsEnabled <- true
}
|> Async.Start

Image created without filetype - need filetype for compression - Angular 2 / Ionic 3

I am trying to compress an image client-side (Angular 2/Ionic 3) and When I log the file that is created by the camera, it says:
"type":null when it should say "type":'image/jpeg'.
I am using the Ionic camera plugin to handle taking a picture or choosing one from the photo library, after that (I assume) the file is created without a type. Every compression tool I have tried has had this problem, and I have run out of options. Is there a way to change the type of a File object?
I created a new Blob with this method and made sure to give it image type:
dataURItoBlob(dataURI, callback): Promise<any> {
return new Promise((resolve, reject) => {
let byteString = atob(dataURI);
//console.log(byteString);
// separate out the mime component
//let mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
// write the bytes of the string to an ArrayBuffer
let ab = new ArrayBuffer(byteString.length);
let ia = new Uint8Array(ab);
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
// write the ArrayBuffer to a blob, and you're done
let bb = new Blob([ab], {type: 'image/jpeg'});
resolve(bb);
})
}
I used it after reading the contents of the image to base64 like this and got the resulting blob with image type:
var readerZ = new FileReader();
readerZ.onload = (e) => {
let data = readerZ.result.split(',')[1];
//console.log(data);
self.dataURItoBlob(data, null).then(blob => {

What is the advantage of using both TypeScript and Traceur? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 years ago.
Improve this question
You can configure TypeScript to output either ES5 or ES6. As long as you want to run your application on a platform that does not natively support ES6 you must compile the ES6 to ES5 using a compiler like Traceur (and including the Traceur runtime library).
Is there any advantage of doing this rather than simply telling TypeScript to output ES5? (I don't expect that the application will ever target native ES6 platforms only)
As far as I have understood you cannot write a program in TypeScript (1.5) that cannot run on ES5 (given that the program compiles and you include the correct libraries). Am I wrong?
Reasons to use Babel or Traceur over TypeScript
So far, the team of Typescript chose not to make the generated code dependent of a runtime. Some features of ES6 can easily be used with TS through polyfills (example: ES6 Promises). Other features require the cooperation of the transpiler and a polyfill (example: ES6 generators). Using a generator with TS is possible (since TS 1.6) but the target must be ES6. That's a good reason to use Babel or Traceur.
Reasons to not use Babel or Traceur over TypeScript
But there are other good reasons for not using Babel and Traceur. Just try to transpile some ES6 code.
The ES6 code:
let list = ['ab', 'cd'];
for (let item of list) {
console.log(item);
}
ES5 produced by TypeScript (using the Playground):
var list = ['ab', 'cd'];
for (var _i = 0; _i < list.length; _i++) {
var item = list[_i];
console.log(item);
}
ES5 produced by Traceur (using the REPL):
$traceurRuntime.ModuleStore.getAnonymousModule(function() {
"use strict";
var list = ['ab', 'cd'];
var $__4 = true;
var $__5 = false;
var $__6 = undefined;
try {
for (var $__2 = void 0,
$__1 = (list)[$traceurRuntime.toProperty(Symbol.iterator)](); !($__4 = ($__2 = $__1.next()).done); $__4 = true) {
var item = $__2.value;
{
console.log(item);
}
}
} catch ($__7) {
$__5 = true;
$__6 = $__7;
} finally {
try {
if (!$__4 && $__1.return != null) {
$__1.return();
}
} finally {
if ($__5) {
throw $__6;
}
}
}
return {};
});
//# sourceURL=traceured.js
ES5 produced by Babel (using the REPL):
'use strict';
var list = ['ab', 'cd'];
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = list[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var item = _step.value;
console.log(item);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator['return']) {
_iterator['return']();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
The solutions from Traceur and Babel are ugly, because the variable list could be an ES6 iterable and these transpilers aren't aware of the types. TypeScript infers that the type of list is an array string[] and it produces just the code for the array.

Resources