lingy 2023-07-27

@slipset has joined the channel

Thank you 🙂

Actually I thought of something that you could help with opinion-wise

Lingy(Perl) has OO interop...

Let me repl a couple things. sec

user=> (import YAML.PP)
YAML.PP
user=> (println (.dump_string (.new YAML.PP) [2 3 4]))
---
- '2'
- '3'
- '4'

also perl eval...

user=> (perl "for my $i (1..4) { print \"$i\\n\" }; 123")
1
2
3
4
123
user=> 

the 123 was to hide a bug I just found 😄

I see that in difference to Clojure, you treat new as a fn (or method). Which makes sense for Perl I guess because it is just that.

In Clojure you’d write (YAML.PP. )

user=> (println (.dump_string (YAML.PP.) [2 3 4]))
---
- '2'
- '3'
- '4'

nil

-> FAIL Installing Time::HiRes failed. See /Users/erik/.cpanm/work/1690475412.86147/build.log for details. Retry with --force to force install it.
-> FAIL Installing the dependencies failed: Installed version (1.9760) of Time::HiRes is not in range '1.9764'
-> FAIL Bailing out the installation for Lingy-0.1.19.
😞

is that cpanm Lingy?

trying on my M1

erik@keep  % perl --version

This is perl 5, version 30, subversion 3 (v5.30.3) built for darwin-thread-multi-2level
(with 2 registered patches, see perl -V for more detail)

Copyright 1987-2020, Larry Wall

With a very fresh cpanm install

erik@keep  % cpanm --version
cpanm (App::cpanminus) version 1.7046 (/opt/homebrew/bin/cpanm)
perl version 5.030003 (perl)

worked here 😕

I get it

That's my fault and I will fix it fast but can you try something?

Run cpanm --look Lingy puts you in a subshell

edit Makefile.PL and set the Time::HiRes version to "0"

then run cpanm .

if you don't mind

Getting there

erik@keep  % lingy -D
Please install Term::ReadLine::Gnu from CPAN
erik@keep  %

do it 🙂

I had to not dep on Term:Readline:Gnu because of windows issues

But the lingy --repl needs it

How do I install that? Perl n00b

cpanm 🙂

D’oh, ReadLine not Readline

M1 Macbook Pro

user=> (macroexpand '(YAML.PP.))
(. YAML.PP new)
user=> (macroexpand '(.new YAML.PP))
(. YAML.PP new)
user=> 

@slipset anyway, in Java everything's an object. so interop is straightforward. In perl the data types are operated on with syntax, operators and keywords.

I want to make a library/namespace for all the keywords

Basically what's in *CORE::

user=> (perl "pack 'WWWW', 65, 66, 67, 68")
ABCD

Right, where pack is an operator or somthing?

I would do

(pl/pack "WWWW" 65 66 67 68)

pack is a perl keyword func

perldoc perlfunc

Ok awesome

It’s been probs 20 years since last time I programmed Perl, so I’m a bit rusty 🙂 I also remember pack as one of the harder things to grok 🙂

I was talking it over with @pez a couple days ago but good to know you agree

So one of the things that Clojure is struggeling with which I believe is being worked on is stuff like:

user> (map Math/abs (range 3))
Syntax error compiling at (*cider-repl ).
Unable to find static field: abs in class java.lang.Math
user> 
Which is just plain old annoying 🙂

@slipset I don't really get why that doesn't work

Can you explain?

Not really. And it’s dinner time :)

Bon appetit 🙂

I think there is a fine line in interop between exposing too much of the idiosyncrasies of the host and hiding too much of them.

Like, from a Clojure point of view I don’t care if Perl has syntax or operators or keywords for doing a thing, I’d just like to gloss over that and perhaps say (perl/+ 5 6) (stupid example since + is in clojure.core.

But it’s also very annoying with leaky abstractions and you’d have to remember that because + is an operator in Perl it behaves slightly different than what pack does since pack is a keyword func.

(if that were the case, I’m being hypothetical here)

(pl/-f path)

Still trying to suss out why (map Math/abs (range 3)) fails

Yah, but you’d might want to expose that throuh clojure.io.perl or something to mimic clojure.io.java

(this is really helpful btw) 😄

But then again, do you expose -f through both clojure.io.perl and perl/-f The former would be for the convenience of the Clojure programmer, the latter for the convenience of the Perl programmer 🙂

Perhaps both?

Lingy starts quickly 🙂

it would be lingy.io.perl or lingy.io.host

And I saw you asked about cljc files. I believe that @borkdude implemented reader conditionals for babashka, you probably want that for lingy as well.

$ time clojure -e '(time 42)'
"Elapsed time: 0.012903 msecs"
42

real	0m0.964s
user	0m2.334s
sys	0m0.085s
$ time lingy -e '(time 42)'
"Elapsed time: 0.07 msecs"
42

real	0m0.136s
user	0m0.108s
sys	0m0.029s

clojure is much faster after starting

(for now 🙂 )

At some point in time I implemented an http client in an early version of https://github.com/planck-repl/planck because I wanted to use it for some simple scripting which needed http/get now, now would I go about using something like Perl libwww (I guess) if I wanted to do (http/get "") from lingy?

I'd have to try. The perl interop is still a wip. Some things don't work as expected. All Lingy data values are class objects so things need to be boxed and unboxed. Some works some not.

And more ideas for free. One thing that Plank was missing at the time was some way to define the packages your program depended on. So It would be neat if lingy had something deps.edn like that also understood how to depend on cpan stuff.

already been discussing that with @seancorfield 🙂

Shadow.cljs has achieved the analogous for NPM; perhaps there is a model to consider

In re the namespaces for common affordances... There is also a pattern. clojure.core and cljs.core are twins. Likewise clojure.pprint and cljs.pprint, clojure.reader and cljs.reader, and a few others. The ClojureScript compiler accepts code that require's http://clojure.xyz, by using http://cljs.xyz instead. This eases writing portable Clojure-ish programs.

In re using Math/abs as if it were a function: in Clojure first-class functions are objects implementing IFn and Math/abs is not such a thing. (macroexpand-1 '(Math/abs 42)) shows (. Math abs 42). But Math (full name java.lang.Math) is host interop, no expectation of similarity on another host.

I pay attention in about 15m

Here now

@phill Lingy is intending to use clojure/core.clj directly. It does so partially now: https://github.com/lingy-lang/lingy/blob/main/perl/lib/Lingy/core.clj

Lingy maps Clojure clojure.lang. namespaces to lingy.lang. equivalents and known Java classes to Perl counterparts

Since Lingy intends to be multi-host I am considering some class name porting to go from java.lang. to host.lang. instead of perl.lang.

whatever the best ways are to get the most use and least duplication out of source files.

Thanks for the insights re the java native Math class

@phill if it were a clojure.lang.Math class then it would implement IFn, right?

Er - All (fn ...) implement Clojure's Java interface "IFn" and I'm sure the Clojure inventors would have made host functions (Java "static methods") first-class if they could figure out how to do so. If a Perl sub {...} could be a first-class function in Lingy, super!

like java.lang.Long vs clojure.lang.Numbers

At this point Lingy doesn't do compilation. It does make Lingy::Fn objects from (fn ...) forms. and those objects are blessed Perl closures (functions)

but compilation (possibly to a super fast VM) is an intended area of research

and the Lingy data types are all tied objects, not first class. for immutability and methods

I think the area for ideal compatibility is pretty much limited to what's documented at https://clojure.github.io/clojure/ ... minus the "clojure.java...." stuff like http://clojure.java.io. Every host differs in those respects. Presumably someone could make a clever asynchronous I/O package that could be used portably, but nothing with blocking I/O will work in JavaScript. The Java-language underpinnings of Clojure are not replicated in ClojureScript, which sort of sets the tone for other ports. According to rumor, ClojureScript is closer to "Clojure-in-Clojure" on account of having used Clojure protocols internally.

but I want them to become HAMT based things

interesting stuff. I'm glad to have people with this level of insight into clojurescript to chat with as I have very littel experience with it so far. but of course I have been wondering WWCSD? 😉

Somewhere, I saw Clojure contrasted with Ruby in this regard. Ruby wraps the whole host standard library, or so I heard. Clojure wraps almost none of it. A striking example is that the (throw ... (catch ...)) model is standard across Clojure-ish ports but it is not possible to write a portable catch clause. The exceptions are host exceptions. So Perl's $@ would fit right in.

I think a portable runtime library might be very welcome, as an add-on, for convenience where the cost of wrapping was not a concern.

I'm thinking about something called LingyVM that might be that

Re throw/catch the https://github.com/kanaka/mal/tree/master/impls does that the same for about 70+ langs

including ruby

or maybe I misundersand you

they all do TCO too (with a test suite that won't finish if implemented wrong, to prove it)

even though Clojure doesn't have native TCO

Lingy has TCO and recur

Yeah Perl has a very nice goto that can go-to a function

There are some exception libraries for Clojure. I think the core language's ideal was to add no run-time cost. Therefore, it uses host exceptions, whatever those might be.

I thought I had seen everything, and then I noticed that in ClojureDart the "catch" clause has an extra parameter because Dart exceptions have the stack trace external to the exception object.

I learned while making my MAL implementation how perl's goto actually works. Iirc it simply does a return at that point and then calls the subroutine that you goto'd to!

Lingy definitely adds runtime cost at this point but since I am free to compile into whatever I can imagine and make it work, the goal is to make it as fast as C extensions in Perl.

So you get a massive performance gains simply by writing parts in a lisp 😂

Of course doing that and achieving really good interop is definitely a science project

➕ 1

@phill did you see my DM to you?

🆒 1

@phill I found that explanation of goto (sub form) in perldoc -f gotot > The "goto &NAME" form is quite different from the other forms of "goto". In fact, it isn't a goto in the normal sense at all, and doesn't have the stigma associated with other gotos. Instead, it exits the current subroutine (losing any changes set by "local") and immediately calls in its place the named subroutine using the current value of @_.

I thought that was both clever and sane