Feed Aggregator Page 664
Rendered on Mon, 19 Oct 2020 16:03:51 GMT
Rendered on Mon, 19 Oct 2020 16:03:51 GMT
via Elm - Latest posts by @rupert Rupert Smith on Mon, 19 Oct 2020 15:17:33 GMT
If a simple Array
is used to hold lines of text, whenever a line is edited, the array will need to be sliced, lines modified, then put back together again. It works fine up to a limit at which point the editor becomes noticeably unresponsive.
I scratched my head over this one for a while, thinking about various tree structures, or skip lists, and so on. Then the answer came to me - make a data structure like a zip list, but use arrays instead of lists. There are lots of packages implementing zip lists, but so far I didn’t see one for arrays.
It will look something like this:
type alias ZippedArray a =
{ head : Array a
, zip : a
, zipAt : Int
, tail : Array a
, length : Int
}
Most successive edits in a text editor will happen on the same line. With this structure, the current line can be the focus of the zipper, and can be modified directly without slicing/appending the array.
When editing moves to a different line, the zipper focus will be shifted. I believe Array.append
is O(log n)? So even for very large text files performance should be good enough when jumping around the file.
Plan is to:
via Elm - Latest posts by @dillonkearns Dillon Kearns on Mon, 19 Oct 2020 14:23:52 GMT
Elm Radio episode 15: Incremental Steps is out. Hope you enjoy!
via Elm - Latest posts by @ronanyeah on Mon, 19 Oct 2020 14:06:29 GMT
I’m averse to monkey patching anything, but I’d like to see what you mean by generator usage. Do you have any code you could post?
via Erlang.org News RSS by on Tue, 13 Oct 2020 00:00:00 GMT
img src=http://www.erlang.org/upload/news/Lukas Larsson and John Högberg from the OTP team are talking about the new JIT implementation for the BEAM in this PODCAST from ThinkingElixir.
via Elm - Latest posts by @francescortiz Francesc Ortiz on Mon, 19 Oct 2020 12:28:12 GMT
Hi! Looks really good. I have made something similar by monkey patching the XMLHttpRequest object. I also implemented handling of generators by using Partial content responses: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/206 think that allows to have websockets or similar stuff.
Do you know if it is possible to achieve the same with the technique you implemented?
via Elm - Latest posts by @Chadtech Chadtech on Mon, 19 Oct 2020 06:17:46 GMT
I dont know exactly off the top of my head, but I dont think I have to do anything special. My test module is usually something like this:
import Main exposing (main)
tests : Test
tests =
test "1 is 1" <| \_ -> Expect.equal 1 1
No real tests here, but it imports Main
, which means that everything in Main
and everything Main
imports will be searched for tests. So any test in any module will be run.
This has the extra benefit of compile errors cause my tests to fail. So usually when I am developing I just run and re-run the tests to see what my compile errors.
via Elm - Latest posts by @lydell Simon Lydell on Mon, 19 Oct 2020 05:24:27 GMT
@Chadtech Thanks for your answer! What does your elm-test
command look like?
via Elm - Latest posts by @Chadtech Chadtech on Mon, 19 Oct 2020 00:09:24 GMT
Yes. I generally put tests inside the module they are meant to test.
A lot of people point out that you shouldnt test the internals of a module. If the tests are inside the module, then you have the opportunity to test internal implementation details. That seems like a valid point to me, and I keep it in mind, but I like the convenience of writing tests right next to the spot that the code is written. I really like that “side-by-side”-ness. Its also easier to make test data and test functions from within a module.
via Elm - Latest posts by @system system on Sun, 18 Oct 2020 23:06:41 GMT
This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
via Elm - Latest posts by @vanniewelt Ondřej Nývlt on Sun, 18 Oct 2020 20:45:52 GMT
On the other hand, Elm type system is limited and we can’t express our domain through it. Our apps deal with complex information and we’d like to have more tools at our disposal than records and tagged sums. We’d like to enforce laws and relations between data, even if we need to pay with steeper learning curve.
Did you consider PureScript? It has more advanced type system, maybe it could satisfy your requirements.
via Elm - Latest posts by @rupert Rupert Smith on Sun, 18 Oct 2020 20:41:10 GMT
Implemented this too. Now arrow keys or page up/down always move in increments modulo the line height with the top or bottom line always holding a full line, depending on which direction you are scrolling towards. That really helped make the scrolling look smooth. I also found that rendering above and below 1 full page of lines removed any flicker on page up and down:
via Elm - Latest posts by @ChristophP Christoph P on Sun, 18 Oct 2020 20:16:39 GMT
Totally with Chad again on this.
While I do believe Elm solved a lot more technical problems than it presented compared to alternatives such as React, I do think Elm comes with its share of organizational, communication problems. I believe is a thing that makes Elm really hard to sell to even open-minded sceptics:
That thing is: Why are there issues and PRs open for years that involve bug fixes? I think they should be closed or worked on. I don’t mind not getting new features but I do think releasing bug fixes in an appropriate amount of time is critical for credibility.
I love Elm and have taught Elm to at least ten people, but this one is really hard to defend IMO.
via Elm - Latest posts by @system system on Sun, 18 Oct 2020 18:57:03 GMT
This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
via Elm - Latest posts by @ronanyeah on Sun, 18 Oct 2020 14:52:31 GMT
For a project using WebCrypto where all text data has to be encrypted on the client side before being sent to the server, and decrypted on the way back, using ports would have been too much overhead.
Since tasks can be used to chain asynchronous work in Elm, I needed to find a way to access the WebCrypto API using a task.
Inspired by this post, I started looking into the feasibility of using service workers as an interface to JavaScript. Since the app already had a service worker due to being a PWA, it seemed like a good match.
On the Elm side I am sending a Http.task
request with a particular method:
serviceWorkerRequest : String -> Json.Decode.Value -> Task Http.Error a
serviceWorkerRequest key body =
Http.task
{ method = "CRYPTO"
, headers = []
, url = "https://" ++ key
, body = Http.jsonBody body
, resolver = resolver
, timeout = Nothing
}
If the service worker identifies this method it intercepts the request:
self.addEventListener("fetch", (e) =>
e.request.method === "CRYPTO" ? e.respondWith(handlers(e.request)) : e
);
I’m using the url to differentiate between ‘actions’, then parsing the body and passing it to the relevant function:
const handlers = async (request) => {
try {
const action = new URL(request.url).host;
switch (action) {
case "decrypt": {
const body = await request.json();
return jsonResponse(decrypt(body));
}
case "encrypt": {
const body = await request.json();
return jsonResponse(encrypt(body));
}
default: {
return errorResponse("unmatched-url");
}
}
} catch (_) {
return errorResponse("execution-failure");
}
};
The Response object can be used to return a result:
const jsonResponse = (data) => new Response(JSON.stringify(data));
Or send back an error if something goes wrong:
const errorResponse = (code) =>
new Response(JSON.stringify({ error: code }), { status: 400 });
Since the service worker is essential for certain features in the app, Elm needs to know if the service worker has been registered successfully:
const { Elm } = require("./Main.elm");
const startApp = (swActive) =>
Elm.Main.init({
node: document.getElementById("app"),
flags: { swActive },
});
const swEnabled = Boolean(
window.navigator.serviceWorker &&
typeof window.navigator.serviceWorker.register === "function"
);
if (swEnabled) {
window.navigator.serviceWorker.register("/sw.js").then(
() => startApp(true),
() => /* registration failure */ startApp(false)
);
} else {
startApp(false);
}
I’m also using clients.claim in the service worker activation handler to ensure all requests start passing through the “fetch” handler immediately:
self.addEventListener("activate", (_event) =>
self.clients.claim()
);
Overall I am happy with the results and would consider using this approach in future to interact with other JS APIs such as localStorage or IndexedDB.
Code:
Caveat:
Service workers are not available in Firefox private browsing or in non-Safari iOS browsers.
via Elm - Latest posts by @system system on Sun, 18 Oct 2020 11:25:08 GMT
This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
via Elm - Latest posts by @francescortiz Francesc Ortiz on Sun, 18 Oct 2020 10:39:28 GMT
Nice! Thanks for sharing the link.
via Elm - Latest posts by @system system on Sun, 18 Oct 2020 09:16:13 GMT
This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
via Elm - Latest posts by @Chadtech Chadtech on Sun, 18 Oct 2020 00:06:25 GMT
Hey thanks for the reply. Yeah I noticed in my original message I didnt go into any of that, which might have been unfair. But I do mostly feel like Elm wasnt presenting any technical barriers to our development.
But I can recall some specific technical matters that seemed pretty tense. So I’ll list some of those out:
Our Elm projects used a lot of ports for http requests. This is because our company already had a strong frontend JS api project that was re-used everywhere for these kinds of requests. One day we tried to do all the http for an Elm project wtihin Elm, just to see how it would go. We quickly ran into problems with how to store and refresh an api token in the Elm model. No one had a really good idea on how to do that in our existing set up. I remember that being an embarrassing day for the pro-Elm side of the discussion because others felt it should be trivial.
This is a non-problem for me now, simply because I now know how to do this well in Elm. We really were on the bleeding edge of Elm development, and I dont think good examples even existed online. I think the competing JS implementation for how to do the API token stuff relied on mutable JS objects, which, I guess would indeed make the problem a breeze, at a big sacrifice to our stability. I remember some of us were looking towards Haskell for inspiration, and I think the leading example relied on typeclasses and very effect-ful and IO heavy operations.
At least in my project, I feel like we suffered a lot of “similar is different than same” problems regarding our UI components. Two spots in the UI would look very similar but had subtle differences, that would tempt me to make a re-usable component. The subtle differences masked the code complexity involved in making one reusable component, and that complexity was great enough to undermine the point of reusable components altogether. So, personally my solution was writing a lot of duplicate code manually. The amount of duplicate code I was writing might not have impressed the Elm-skeptics in the company.
Just like the point above, this just is not a problem for me anymore. It took time, but I and seemingly the Elm community as a whole gradually learned good ways of making code re-usable in Elm. In some ways this is not even an Elm specific problem. Reusability is just a nut you have to crack in every language and I could have gotten it wrong in React too.
As the 0.19 release approached, I think we knew the api for url navigation in 0.19 was quite strict, and that in 0.19 you could only do url navigation if your Elm app had control over the whole page. Well, guess what! We had a lot of small Elm widgets that did navigation, so in order to migrate we would probably have to come up with our own solution that involved a lot of ports. I recall someone saying “Evan thinks we are stupid” in reflection on this, as in, Evan wrote an api to force us to take a certain approach, which implies he doesnt think we can make this choice ourselves.
It seems like the Elm-skeptics had a point, that Evan did in fact add difficulty to our ability to upgrade. Whether or not this additional difficulty on our end was justified in the grand scheme of things, or whether or not it was a good design to begin with, are two questions I just dont know the answer to. But, either way, the whole topic was not relevant in any practical way: we were not at the moment trying to upgrade to 0.19; we didnt necessarily even need to upgrade to 0.19, 0.18 was doing great; and the upgrade path we did have to 0.19 was not in fact overwhelmingly difficult. So, in my view, which sides of the discussion were right had little relevance to writing Elm code; but it was probably taken as a sign that Elm is going to create big problems for us anyway.
via Elm - Latest posts by @ianmackenzie Ian Mackenzie on Sat, 17 Oct 2020 20:36:34 GMT
This is a very cool project! And @mattpiz is completely correct that this kind of advanced use of textures is beyond what’s possible in elm-3d-scene
currently, although supporting custom shaders and fixing the 65536 vertex limit are certainly on the roadmap. Standard normal maps should be supported soon, though, I have everything working locally (as far as I can tell!) and just need to do some more testing/playing around with the API.
via Elm - Latest posts by @mattpiz Matthieu Pizenberg on Sat, 17 Oct 2020 20:16:29 GMT
Recently, I’ve been working on visualizations of depth maps in the browser and it turns out elm-explorations/webgl is great for that! This is a recap of how I used it and here is the demo.
I’m currently working on a project doing 3D reconstructions of surfaces with very small surface variations such as textile or coins. We want to make what we are building easy to use for the other participants in the project that are neither scientists nor programmers. So making a webapp, based on wasm (from Rust) and Elm for the frontent is our current choice.
The approach we are using for the 3D reconstruction is called photometric stereo. It is based on images from the same point of view (but with varying lighting conditions). For this reason, the resulting 3D reconstruction is a 2D image with depth (from the camera) and normals for every pixel. In this research field, they are called depth maps (and normal maps), but they are also sometimes called height maps if the reference isn’t the camera. Here is an example of a pair of depth map (monochrome) and normal map (RGB) generated from photometric stereo.
WebGL works by putting together two programs called a vertex shader, and a fragment shader. It sounds fancy but it’s rather simple in fact. A 3D model, from the point of view of a GPU is just a set of 3D points (called vertices, or vertex), and instructions to display them. The vertex shader takes care of moving vertices, projecting their coordinates from the 3D world frame reference to the coordinates in the canvas of the web page. Then the fragment shader fills the canvas for every pixel interpolating colors with the nearest vertices. Shaders in WebGL are written in a language called GLSL. Here are the shaders for the demo web page.
// vertex shader (executed for each vertex)
void main () {
// extract RGBA from the texture at the given coordinates
vec4 tex = texture2D(texture, mapCoordinates);
// extract the normals to pass them to the fragment shader
vnormal = vec3(2.0 * tex.xyz - 1.0);
// use the camera projection matrix to transform points from world 3D
// coordinates to coordinates in the canvas.
// Note that we extract the "depth" (Z) from the 4th component of the texture (tex.w).
gl_Position = modelViewProjection * vec4(position, -tex.w * scale, 1.0);
}
// fragment shader (executed for each pixel)
void main () {
// normalizing the interpolated vnormal for the given pixel
vec3 normal = normalize(vnormal);
// computing the light intensity on that pixel (the color)
float intensity = dot(normal, directionalLight);
gl_FragColor = vec4(intensity, intensity, intensity, 1.0);
}
You may have spotted that only one texture is used. That’s because we pack together the normals (RGB) and the depth into a single PNG image with an alpha channel for the depth (RGBA). If you want to know more about WebGL, have look at the WebGL Fundamentals guide.
If you know 3D and JS, you know threejs. And if you know 3D and elm, you should know elm-3d-scene! It’s an amazing project so kudos to Ian who is leading that front. It’s still very young though. And at the time of doing that experimentation, it hasn’t stabilized yet on a way to use custom shaders, or geometry that is not internally indexed, currently limited to 16bits so a maximum of 65536 vertices per object. So unfortunaley we cannot directly use it for our geometry. But I hope this experiment will help shaping ways of doing it in the future. I am heavily using elm-3d-camera though, which helps a great deal being confident in the matrices being built for the camera viewpoint. Combined with elm-geometry, these enabled building the panning + orbiting + zooming interaction of the viewer. You can zoom with the mouse wheel, orbit by clicking and dragging, and pan by also holding the ctrl
key while dragging.