Feed Aggregator Page 1
Rendered on Wed, 30 Oct 2024 16:13:08 GMT
Rendered on Wed, 30 Oct 2024 16:13:08 GMT
via Planet Lisp by on Wed, 27 Sep 2023 16:31:00 GMT
Greenspun's tenth rule of programming states
Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug ridden, slow implementation of half of Common Lisp.Observe that the Python interpreter is written in C.
In fact, most popular computer languages can be thought of as a poorly implemented Common Lisp. There is a reason for this. Church's lambda calculus is a great foundation for reasoning about programming language semantics. Lisp can be seen as a realization of a lambda calculus interpreter. By reasoning about a language's semantics in Lisp, we're essentially reasoning about the semantics in a variation of lambda calculus.
via Planet Lisp by on Fri, 15 Sep 2023 15:07:23 GMT
For those who don’t know and who didn’t see the banner :D I am creating a Common Lisp course on the Udemy platform (with complementary videos on Youtube). I wanted to do something different and complementary than writing on the Cookbook.
I worked on new videos this summer and I just finished editing the subtitles. I have added 17 videos (worth 1h30+ of code-driven content) about Common Lisp macros!
We cover a lot of content: quote, backquote and comma, “,@”, comparison with C macros, comparison with functions, GENSYM and variable capture, useful patterns (call-with...), compile-time computing, read-time evaluation... (full summary below)
I recorded the last one, about the MACROSTEP tool, inside the Lem editor. It’s short, you should have a look at how this new editor looks like. (I’m very excited about it. Did I say I started develop a Magit-like plugin for it?)
The whole course is for beginners in Lisp, although not total beginners in programming. This chapter is, logically, a bit more difficult than the others. If you didn’t write small Common Lisp programs yet, be gentle with yourself and stop if you don’t understand. (you can ask questions in the Udemy forum, of course) In your case I would advise to watch the introductory one, the comparison with C macros, the video on QUOTE, the “functions VS macros” one, and then carry on at your rhythm. Be sure to work on the previous chapters before tackling this one.
This is what we see on the topic of macros. For a full overview of the course, what I want to do next (if you subscribe now, you’ll get new content for the same price) and read others’ feedback, see its GitHub project page (there are six more chapters including getting started, functions, iteration, condition handling...).
Table of Contents
Macros do not evaluate their arguments and expand to new code at compile time. What does that mean? A quick intro before diving deeper.
Lisp macros are NOT manipulating text, unlike C. Text leads to many unnecessary problems. We have a fun tour of a trivial need yet complicated issue in C that is easily done in Common Lisp.
QUOTE does not evaluate its argument.
What we see: how to use QUOTE outside macros. Data takes the shape of code. We pair it with eval and we go full circle. We introduce the need to extrapolate values inside a quote.
What we see: how we extrapolate variable values. How they can help create data structures. Real world examples.
Four tips to recognize if you are using a function or a macro, and why it matters.
Macros do NOT replace functions!
What we see: they are not higher-level functions. The subtle but logic need to re-compile functions using macros.
Introducing MACROEXPAND.
Keeping compile-time computing in mind (more on that later). A look at a function’s disassembly. So... you might not need a macro yet ;)
What we see: when use it, understanding the common error messages, passing body forms to our macro. Our first macro model.
What we see: how &body differs to &rest. Macro parameters: lots of possibilities, but some conventions carry meaning. Our own DOLIST macro. Our second macro model you can follow.
We build our first macro with backquote and comma-splice, even a quote followed by a comma. We use macroexpand.
What we see: what is variable capture and how to avoid it. Writing our own REPEAT macro. A little discussion about Common Lisp VS Scheme macros. GENSYM can be used outside macros too.
At this point you know enough to write all common macros. See the exercises for easy and not-so-easy ones.
We saw there can be subtle pitfalls when we write a macro. This pattern allows to offload most of the work to a function, which presents many advantages. We demo with our REPEAT macro.
When writing macros, we have the full power of Common Lisp at compile time. This gives great tools to the developer: early type errors and warnings, faster runtime.
What we see: a simple example, writing a scientific macro for conversion of unit at compile time, existing libraries for that, introduction to dispatching macro characters and reader macros.
What we see: other languages don’t have macros but can manipulate Abstract Syntax Trees. Code as lists of symbols is not the same, we would need a third-party library to manipulate a Lisp AST proper. This doesn’t prevent us to develop crazy macros though, see this library adding Haskell-like type checking on top of Common Lisp, in pure CL macros.
defstar allows to specify a function’s arguments’ types, Serapeum’s ecase-of does exhaustiveness type checking. At compile time, of course.
A symbol macro is not your everyday Lisp development tool, but it expands your toolbet. Again.
Macros occur at compile-time. But Common Lisp blurs the lines between read time, compile time and run time. This allows to execute code at READ time.
Macrostep is an editor extension that helps understand our macro expansions. It is only available in Sly and Lem. We demo with the Lem editor.
Thanks for your support, it does make a difference (I am self employed, I don’t earn millions and I’d love to spend *even more time* on CL resources and projects). If you want to learn what I do for the Lisp community and why you should buy my course, read more on Github.
My complementary Lisp videos are on Youtube.
Don’t hesitate to share the link with a friend or a colleague :) Thanks, and happy lisping.
A demo about web development has been recorded and is coming.
ps: we just got a Dockerfile for CIEL, which is then easier to test, thanks to a “student” of my course. Thanks, @themarcelor. It will be on Dockerhub in due time.
The Udemy course by @vindarel is the best introductory material for a fast and practical intro to Common Lisp.
(thanks <3)
A wonderful course for someone with cursory knowledge of lisp. I’ve dipped my feet many times now, but always struggled to wrap my head around everything. This course really helped give me greater confidence in how to start a project. I really enjoyed the focus on having an executable early. The Lisp-2 reveal was beautiful and made me finally understand the difference. Thanks a lot!
Simon, August of 2023. (thanks <3 )
via Elm - Latest posts by @LTstrange LTstrange on Sat, 26 Aug 2023 14:50:09 GMT
Hi,
I’m pretty new to elm and front-end. And I encountered the same problem which has been solved in this previous post 4088, but it didnt work for me.
edit: Neither worked on github.io
, here is my github repository, in case you want to check it.
I’m using vscode’s live server extention to host in local. And I have tried to set the proxy of it based on that post:
# settings.json
{
"liveServer.settings.proxy": {
"enable": true,
"baseUri": "/index.html",
"proxyUri": "http://localhost:5500/index.html?"
}
}
And also set it in varies way. It never work.
The elm code I wrote is the guide code:
-- Main.elm
module Main exposing (main)
import Html exposing (..)
import Html.Attributes exposing (class, src, alt, href)
import Browser
import Url
import Browser.Navigation as Nav
-- MAIN
main : Program () Model Msg
main = Browser.application
{ init = init
, update = update
, view = view
, subscriptions = subscriptions
, onUrlChange = UrlChanged
, onUrlRequest = LinkClicked
}
-- MODEL
type alias Model =
{ key : Nav.Key
, url : Url.Url
}
init : () -> Url.Url -> Nav.Key -> ( Model, Cmd Msg )
init _ url key = ( Model key url, Cmd.none )
-- UPDATE
type Msg
= LinkClicked Browser.UrlRequest
| UrlChanged Url.Url
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
LinkClicked urlRequest ->
case urlRequest of
Browser.Internal url ->
( model, Nav.pushUrl model.key (Url.toString url) )
Browser.External href ->
( model, Nav.load href )
UrlChanged url ->
( { model | url = url }
, Cmd.none
)
-- VIEW
view : Model -> Browser.Document Msg
view model =
{ title = "URL Interceptor"
, body =
[ text "The current URL is: "
, b [] [ text (Url.toString model.url) ]
, ul []
[ viewLink "/home"
, viewLink "/profile"
, viewLink "/reviews/the-century-of-the-self"
, viewLink "/reviews/public-opinion"
, viewLink "/reviews/shah-of-shahs"
]
]
}
viewLink : String -> Html msg
viewLink path =
li [] [ a [ href path ] [ text path ] ]
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions _ =
Sub.none
Then compile it use elm make
and uglifyjs
to main.js
, which linked in index.html
:
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src="main.js"></script>
<link rel="stylesheet" href="./assets/style.css">
<link rel="icon" href="assets/logo.svg">
</head>
<body>
<script>var app = Elm.Main.init();</script>
</body>
</html>
Is there any information I need to offer? Just mentioned below.
Please help me,
LTstrange.
via Planet Lisp by on Fri, 25 Aug 2023 12:45:54 GMT
I've been debating opening up a Patreon for many years and I've always been hesitant about accepting donations from people, but I think it's finally time to change my mind on that!
I've been working full time on Kandria and associated projects since 2020, and continue to do so today. All of the work that I've done as part of that has been released as open source software, including Kandria itself as well as the engine it runs on, Trial.
Since the release, I've mostly focused on support and the pre-pre-production of my next title, which primarily involves adding new features to Trial that are necessary to create a full-3D game. I can't yet announce much about the game itself, other than that it is a character action game, meaning it features third-person hack and slash focused on slick and satisfying combat.
Unfortunately the release of Kandria has not gone as well as I would have liked, and revenue from it is minimal. Most months I receive only about 200 bucks from Steam, which as you might imagine is not enough to sustain myself full-time, let alone any other artists that are necessary to produce another high-quality game.
So I am finally opening myself up for continued public funding. I know people have wanted to support me in the past before, and I've always been hesitant about accepting that. But now with the financial pressure increasing, I think it's finally time to let people that want to be generous, actually be generous!
Aside from simply funding my existence and allowing me to continue to produce high-quality open source libraries and applications, art, writing, and games, I'm also committing to a couple of extra features:
Every month I'll produce a patron-only update about what's currently happening with the development. This will also include development insight and details that won't be published elsewhere.
I'll also commit to a monthly art stream where I doodle around, and higher-tier patrons can request sketches from me.
Any patron will be able to submit their name or a name of their choosing for inclusion in the credits of any game in production during their backing.
Higher-tier patrons will also receive access to early game prototypes and demos.
You'll be able to directly ask me questions in the comments of the monthly updates and in the stream chat.
If you use Discord, you'll receive access to a special role and patron-exclusive chatroom on my Discord server.
An eternal feeling of debt and gratitude towards you.
Now I'm going to go back to working on Trial and the unannounced game. In the meantime, please consider backing me. There should already be a monthly update about the state of things out that's only accessible to patrons. In any case, thank you very much for your continued support, and I hope I'll be able to see you among the backer list soon!
via Elm - Latest posts by @bwanab Bill Allen on Fri, 25 Aug 2023 11:32:46 GMT
Thanks for the reply. It did help to unblock me some. After moving the calc from the table body to the table it fixed the specific problem I mentioned. Now Safari behaves like Firefox and Chrome with respect to aspect ratio. But, now the viewport seems to have become strangely quantized where before in Chrome and FF it was pretty smooth. Alas.
Do you, or anybody else who might be reading this have any full samples of a browser application that uses the elm-bootstrap library? I haven’t been able to find any. I’m starting to wonder if maybe recoding with a different css library might be a better approach.
via Elm - Latest posts by @eberfreitas Eber Freitas Dias on Thu, 24 Aug 2023 13:24:30 GMT
I’m really enjoying the great content you’ve been sharing, @dwayne. Thanks a lot!
via Elm - Latest posts by @passiomatic Andrea Peltrin on Thu, 24 Aug 2023 09:42:50 GMT
A few suggestions:
html
and body
elements to height: 100% so your UI will stretch to the full browser viewport height.link
to bootstrap CDN to head
display: flex
with flex-direction: column
container, which contains a header
a main
and a footer
elements. main
contains the table you are using for the game board.Hope this help to unblock you a little more.
via Elm - Latest posts by @Ron on Thu, 24 Aug 2023 01:47:53 GMT
I read only the first para and got some ideas (and made some silly mistakes) I will try to solve it again - and then read the full reply - thanks for the detailed reply
via Elm - Latest posts by @Ron on Thu, 24 Aug 2023 01:45:38 GMT
Thanks for introducing me to Ellie app, I googled Elm formatters and evals but never found it.
Actually I want to write an RxJS clone and when choosing between learning Haskell or Elm - I chose Elm because Wikipedia lists it as FRP and also because I’d get visual feedback making webapps. It is surprising to know Elm isn’t FRP anymore.
via Elm - Latest posts by @novid Novid Emami on Wed, 23 Aug 2023 21:11:59 GMT
You could have a look at URL handling with Browser.application or the missing part of the Elm guide
via Elm - Latest posts by @LTstrange LTstrange on Wed, 23 Aug 2023 15:07:53 GMT
Hi,
I’m following the offical guide, and reading the URL Parsing chapter, but the Synthesis part’s code is TODO
. So I come here to send a feedback.
via Elm - Latest posts by @bwanab Bill Allen on Wed, 23 Aug 2023 14:29:26 GMT
I’ve built a simple Othello/Reversi app as a front end to a machine learning project I’ve been doing to implement an Othello playing bot. I’m not a front end dev, but I know a lot more about it now than I did a week ago :).
I want the Othello board to be based on the size of the browser and responsive to both width and height of the browser. This is a compromise that I think is needed since I want it to be playable on a small screen (phone) as well as a large screen. Width was easy, in fact it seemed to be the default behavior, but it took a bit of css research to figure out how to make height responsive. The problem is that while my solution works with Chrome, Vivaldi, and Firefox, it doesn’t in Safari and all the iPhone browsers (since they’re all required to use the same display engine). I don’t have an Android phone, so it hasn’t been tested there.
Here is the code that made height responsive:
reTbody : List String -> Playing -> Table.TBody Msg
reTbody board playing =
Table.tbody [ Html.Attributes.style "height" "calc(75vh - 16px)"] (boardTable board playing)
The game URL is here, if that would help to visualize it (sorry, it isn’t very pretty): http://reversi.k2bea.org.
Any ideas on why it wouldn’t work in Safari and how it could be made to work?
via Elm - Latest posts by @dwayne Dwayne Crooks on Wed, 23 Aug 2023 10:33:57 GMT
Thanks for finding these interesting ways to improve performance. I’d have to try them out myself at some point but also feel free to share your sample implementation.
via Elm - Latest posts by @dwayne Dwayne Crooks on Wed, 23 Aug 2023 10:25:18 GMT
Learn how smart constructors, JSON decoders, and “Parse, don’t validate” help you write better event listeners.
via Elm - Latest posts by @mburri Max Burri on Wed, 23 Aug 2023 10:19:53 GMT
Hey Ron
You commited no sins to make your app “non-reactive” - thanks to the Elm Architecture…
But you are just not finished yet.
If you delete everything in the Password field, your DelPass
msg is triggered with x
being an empty string in your update function. There, you are validating the now empty input string - and get all validation errors. You have to handle the case where x
is an empty string.
Btw. since fdbk
in your model is derived from model.pass
I’d suggest to not keep track of the feedback in your model at all and move the validation to your view function.
If you want to clear Password2 - you have to clear pass2
in your model. I think it is save to clear pass2
every time the value of pass
changes.
To finally answer your questions
passwordsAreSame
in your modelpass2
if pass
changes…pass
is actually empty - then you have to look at your update function and fix the issue…False
. Again, empty strings are a special case - you probably never want to enable the button if pass
is emptyList.concatMap
- go and check the documnetation of the List package: (List - core 1.0.5)Some general (subjective) feedback on your code:
feedback
instead of fdbk
or passwordAgain
instead of pass2
. Your future self will thank you for this.PasswordChanged
and PasswordAgainChanged
instead of DelPass
and DelPass2
. First, I thought these messages are triggered when the user deletes the password input.I hope my feedback is helpful and leads you on the right track…
via Elm - Latest posts by @rupert Rupert Smith on Wed, 23 Aug 2023 07:18:33 GMT
BTW, we often share code snippets using Ellie. Here is one I created from your pastebin code:
https://ellie-app.com/nJFdVhY7d6ba1
Elm isn’t FRP (Functional Reactive Programming) any more, it was prior to 0.17. In version 0.17 the architecture changed from signals and FRP to TEA (The Elm Architecture). The elm guide describes this: The Elm Architecture · An Introduction to Elm
Sorry, doesn’t really answer your questions, but I thought these might be some helpful pointers to get you started working with Elm.
via Elm - Latest posts by @Ron on Wed, 23 Aug 2023 01:50:23 GMT
My sign-up mini app is not reactive. Things flow in one-way only - so (I maybe wrong) my app is not reactive.
I am a Python programmer and never touched F[R]P before. I read till Forms · An Introduction to Elm and wanted to add some extras.
Goals:
Code: module Main exposing (Issue, Model, Msg(..), PasswdFeedback, init, inp, main, up - Pastebin.com
Issues
Questions
showFb : String -> List msg
and then do List.map showFb feedbacks
I get List (List msg)
so how to flatten it to List map
?I thought I’d post this in Request and Feedback - but since my app goals are not met - I am asking under the Learn tag.
via Elm - Latest posts by @Birowsky on Tue, 22 Aug 2023 15:27:54 GMT
Well gentlemen, I managed to pull this off. Here are the notes for my future self, or anyone else:
import * as fs from 'fs-extra';
import * as path from 'path';
export {
removeUnusedElmModules,
}
function removeUnusedElmModules(
directory = 'src/scripts',
entryModuleName = 'MainModule',
excludeDirectories = [
'src/scripts/Api',
'src/scripts/ElmFramework',
'review/src',
],
): void {
const allElmPaths = findFiles(directory, excludeDirectories, '.elm');
const allUsedElmPaths = getUsedElmPaths(directory, entryModuleName);
const allUnusedElmPaths = excludeMembers(allElmPaths, allUsedElmPaths);
removeFiles(allUnusedElmPaths);
removeEmptyDirectories(directory);
}
function getUsedElmPaths(directoryPath: string, entryModuleName: string): string[] {
return getUsedModules(directoryPath, entryModuleName)
.map(moduleName => getModulePath(directoryPath, moduleName));
function getUsedModules(baseDir: string, entryModuleName: string): string[] {
const visitedModules = exploreModule(baseDir, new Set(), entryModuleName);
return Array.from(visitedModules);
}
function exploreModule(baseDir: string, visitedModules: Set<string>, moduleName: string): Set<string> {
if (visitedModules.has(moduleName)) return visitedModules;
const modulePath = getModulePath(baseDir, moduleName);
if (!fs.existsSync(modulePath)) return visitedModules;
visitedModules.add(moduleName);
const content = readModuleContent(modulePath);
const imports = extractImports(content);
imports.forEach((importName) => exploreModule(baseDir, visitedModules, importName));
return visitedModules;
}
function readModuleContent(modulePath: string): string {
return fs.readFileSync(modulePath, 'utf-8');
}
function extractImports(content: string): string[] {
return (content.match(/^import\s+([^\s]+)/gm) || []).map((line) => line.split(' ')[1]);
}
function getModulePath(baseDir: string, moduleName: string): string {
return path.join(baseDir, moduleName.replace(/\./g, '/') + '.elm');
}
}
function removeFiles(filePaths: string[]): void {
filePaths.forEach(filePath => {
try {
fs.unlinkSync(filePath);
} catch (error) {
console.error(`Failed to delete ${filePath}:`, error);
}
});
}
function excludeMembers(toChange: string[], excludeThese: string[]): string[] {
const setB = new Set(excludeThese);
return toChange.filter(item => !setB.has(item));
}
function findFiles(directory: string, excludedPaths: string[], extension: string): string[] {
return excludedPaths.includes(directory)
? []
: fs.readdirSync(directory).flatMap(decider);
function decider(candidate: string): string[] {
const fullPath = path.join(directory, candidate);
const stat = fs.statSync(fullPath);
return stat.isDirectory()
? findFiles(fullPath, excludedPaths, extension)
: path.extname(candidate) === extension
? [fullPath]
: [];
}
}
function removeEmptyDirectories(directory: string): void {
const files = fs.readdirSync(directory);
files.forEach(file => {
const fullPath = path.join(directory, file);
const stat = fs.statSync(fullPath);
if (stat.isDirectory()) {
removeEmptyDirectories(fullPath);
}
});
if (fs.readdirSync(directory).length === 0) {
fs.rmdirSync(directory);
}
}
Jeroen, I’ll try to reach out in a couple of days to see if you can debug the elm-review issues.
Cheers!
via Elm - Latest posts by @absynce Jared M. Smith on Tue, 22 Aug 2023 14:54:09 GMT
Hey folks! Join Mika Naylor on her journey with functional programming through the doors of Elm to Elm Land and beyond.
Elm Town 63 – Opening the doors of functional programming:
https://elm.town/episodes/elm-town-63-opening-the-doors-of-functional-programming
YouTube (audio-only)
Elm Town 63 – Opening the doors of functional programming
Thanks to Mika Naylor for coming to Elm Town.