Clojure generate externs ext.js files for ClojureScript - javascript

I'm trying to parse some Javascript libraries with Clojure to generate externs files for using them in ClojureScript.
Clojure read-file function
I stumbled across and old Clojure source file that intended to do this, but has some deprecated code and doesn't work anymore, so I wanted to take some concepts from it and start over.
From the script of the Gists above I started with the read-file function.
(ns n01se.externs-for-cljs
(:require [clojure.java.io :as io]
[cljs.compiler :as comp]
[cljs.analyzer :as ana]))
(defn read-file [file]
(let [eof (Object.)]
(with-open [stream (clojure.lang.LineNumberingPushbackReader. (io/reader file))]
(vec (take-while #(not= % eof)
(repeatedly #(read stream false eof)))))))
First Question: why eof is represented by a plain Object ?
Parsing Javascript
Then I fed this Javascript source code to the read-test-file function:
yayQuery = function() { // <= EXCEPTION: read exception at {
var yay = {};
yay.sayHello = function(message) {
console.log(message);
}
yay.getMessage = function() {
return 'Hello, world!';
}
return yay;
};
I startup the cider debugger and start checking the loop and as expected I get yayQuery.
So I got:
yayQuery
=
function
()
Until the reader gets to {, and this exception pops up.
Map literal must contain an equal number of forms.
Prevent read from "evaluating" ?
Hypothesis: Looks like the read function tries to interpret { so starts searching for a key ?
Second Question: If the hypothesis above is true. Can I avoid read from evaluating the code ?
I tried binding *read-eval* to false but I still got the same exception:
(ns externer.core
(:require [clojure.java.io :as io])
(:gen-class))
(defn read-test-file [file]
(let [eof (Object.)]
(with-open [stream (clojure.lang.LineNumberingPushbackReader. (io/reader file))]
(binding [*read-eval* false]
(take-while #(not= % eof)
(repeatedly #(read stream false eof)))))))
(defn -main
[& args]
(read-test-file (first args)))
I also tried edn also because of the unsafety of using read but I still got the same exception as above.
(ns externer.core
(:require [clojure.java.io :as io])
(:gen-class))
(defn read-test-file [file]
(let [eof (Object.)]
(with-open [stream (clojure.lang.LineNumberingPushbackReader. (io/reader file))]
(take-while #(not= % eof)
(repeatedly #(edn/read {:eof eof} stream))))))
(defn -main
[& args]
(read-test-file (first args)))
Final Question: There's another more safe/correct way to generate externs automatically ?

Related

MaxPriorityQueue is not defined

I am experiencing something that is confusing me.
While working through problems in javascript on leetcode, I came across a solution that implemented a MaxPriorityQueue in the solution.
The posted solution was:
Finally, there's a Max/MinPriorityQueue for JavaScript!
add -> enqueue( )
remove -> dequeue( )
highest number (peek) -> front( )
.element -> actual value
var lastStoneWeight = function(stones) {
const m = new MaxPriorityQueue()
for(const w of stones) m.enqueue(w)
while(m.size() > 1){
const diff = m.dequeue().element - m.dequeue().element
if(diff > 0) m.enqueue(diff)
}
return m.size() === 0 ? 0 : m.front().element
};
I tried to implement this myself in my own environment and get:
const m = new MaxPriorityQueue();
^
ReferenceError: MaxPriorityQueue is not defined
at lastStoneWeight (C:\Users\steph\Desktop\coding-projects\learning-js\leetcode\last-stone-weight.js:55:13)
at Object.<anonymous> (C:\Users\steph\Desktop\coding-projects\learning-js\leetcode\last-stone-weight.js:66:13)
I went and plugged the same code into leetcode and it ran without a hitch.
I tried to find documentation on a MaxPriorityQueue object but anything using a MPQ was implemented from scratch.
If someone could shed a bit of light on why this will not run in my personal environment, (nodejs, VSCode), I would appreciate it.
This is because you have #datastructures-js/priority-queue library imported in the JS runtime by default. It is mentioned https://support.leetcode.com/hc/en-us/articles/360011833974-What-are-the-environments-for-the-programming-languages-.
In your own run time, you will have to import it as
const {
PriorityQueue,
MinPriorityQueue,
MaxPriorityQueue,
} = require('#datastructures-js/priority-queue');
or
import {
PriorityQueue,
MinPriorityQueue,
MaxPriorityQueue,
ICompare,
IGetCompareValue,
} from '#datastructures-js/priority-queue';

How can I call an individual Idris function from JavaScript?

Suppose I have a function in Idris that does some computation. For simplicity, let it be stringly typed for now.
f: String -> String
How can I compile this function to JavaScript so that it can then be called from any ordinary JavaScript code?
If that is too easy, suppose f, instead of String, deals with Double or even a custom Idris data type.
I know I can compile a whole module with a Main.main function and a more or less inscrutable blob of JavaScript will be output. Can I maybe extract my function from there by hand? How should I go about it?
P.S. Despite my answering myself, I am still looking for a better solution, so welcome.
Using this example, it seems at least with the Node backend this is doable. I've marked interact as export and added a library descriptor:
module Main
import Data.String
f: Double -> Double
f x = x + 1
export interact: String -> String
interact s = let x = parseDouble s in
case x of
Nothing => "NaN"
Just x => show (f x)
main: IO ()
main = do
s <- getLine
putStrLn (interact s)
lib : FFI_Export FFI_JS "" []
lib = Data String "String" $
Fun interact "interact" $
Fun main "main" $
End
I have then compiled with the --interface flag (this fails with --codegen javascript...):
idris --codegen node --interface --output ExportToJS.js ExportToJS.idr
and the resulting .js file has this at the end:
module.exports = {
interact: Main__interact,
main: Main__interact
};
}.call(this))
This should allow you to do require("./ExportToJavaScript.js").interact("42") from Node, and there is probably an equivalent to use from a browser.
Yes, you can extract any function by hand.
Build a module as follows:
module Main
import Data.String
f: Double -> Double
f x = x + 1
interact: String -> String
interact s = let x = parseDouble s in
case x of
Nothing => "NaN"
Just x => show (f x)
main: IO ()
main = do
s <- getLine
putStrLn (interact s)
Compile it as follows:
% idris --codegen javascript --output Main.js Main.idr
A file called Main.js will be created. There will be several megabytes of more or less inscrutable JavaScript code, just as you say.
Edit this file by hand and edit it similarly to this:
--- Resistors.js
+++ Resistors-default.js
## -1,7 +1,5 ##
"use strict";
-(function(){
-
const $JSRTS = {
throw: function (x) {
throw x;
## -36130,7 +36128,3 ##
}
}
}
-
-
-$_0_runMain();
-}.call(this))
Now notice this JS file has comments in it marking the JS functions with their Idris names. For instance, corresponding to our interact function there will be located this JS function:
// Main.interact
function Main__interact($_0_arg){
const $_1_in = Data__String__parseDouble($_0_arg);
if(($_1_in.type === 1)) {
const $cg$3 = Main__bestMatch_39_($_1_in.$1, Main__manyResistors_39_());
let $cg$2 = null;
$cg$2 = $cg$3.$1;
return Prelude__Show__Main___64_Prelude__Show__Show_36_Schema_58__33_show_58_0($cg$2);
} else {
return "NaN";
}
}
If you attach this JS file to a web page as a script, you may then open JS console in a browser and interact with your Idris functions, like this:
Main__interact("10")
"11"
Hope this helps!

TypeScript 3.0 error on `unknown` usage

Here, I test TypeScript3.0 unkown type.
https://blogs.msdn.microsoft.com/typescript/2018/07/12/announcing-typescript-3-0-rc/#the-unknown-type
TypeScript 3.0 introduces a new type called unknown that does exactly that. Much like any, any value is assignable to unknown; however, unlike any, you cannot access any properties on values with the type unknown, nor can you call/construct them. Furthermore, values of type unknown can only be assigned to unknown or any.
I play with some Church eoncoding stuff, and testing unknown type to every argument of functions, I have an error as below:
const log = (m: unknown) => {
console.log(m); //IO
return m;
};
const I = (x:unknown) => x;
const L = (x:unknown) => (y:unknown) => x;
const P = (x:unknown) => (y:unknown) => (z:Function) => z(x)(y);
//z is a binary operator Function!
const Left = L;
const Right = L(I);
log("Left Right test---------");
log(
Left("boy")("girl") // boy
);
log(
Right("boy")("girl") //TypeScript Type Error here
);
Error:
church.ts:20:9 - error TS2571: Object is of type 'unknown'.
20 Right("boy")("girl")
~~~~~~~~~~~~
Just in case, this is well-tested in vanilla JS, but I simply want to know how to resolve this error without using any type.
Thanks.
Quite simply here I don't think you should use unknown but rather a generic function as there are obvious relations between the argument to L and the final return type:
const I = (x:unknown) => x;
const L = <T>(x:T) => (y:unknown) => x;
const Left = L;
const Right = L(I);
log("Left Right test---------");
log(
Left("boy")("girl") // boy
);
log(
Right("boy")("girl") //all ok
);
I would use unknown much like any as a last resort type when the type is not only unknown when writing the function (where we can use regular types) but also unknowable when calling the function (this is when I would generic type parameters).
If for some reason generics are not feasible the only way to get around this is with a type assertion, as you have information the type system lost in this case:
(Right("boy") as ((x:unknown)=> unknown))("girl") //all ok

Does Scalatags generate HTML or Javascript?

I saw some Scala code that appears to generate HTML...
def pagePlay: TypedTag[dom.raw.HTMLElement] = div{
val levels = Array(
(10, "Easy game; you are allowed 10 misses."),
(5, "Medium game; you are allowed 5 misses."),
(3, "Hard game; you are allowed 3 misses.")
)
div(
p("Inspired from ")(a(href:="http://www.yiiframework.com/demos/hangman/", target:="_blank","Yii's demo")),
p("This is the game of Hangman. You must guess a word, a letter at a time.\n" +
"If you make too many mistakes, you lose the game!"),
form(id := "playForm")(
for((level,text) <- levels) yield {
val levelId = s"level_${level}"
div(`class`:="radio")(
input(id:=levelId, `type`:="radio", name:="level", onclick:={ ()=>
Model.level() = level
}, {if(level == Model.level()) checked:="checked"}),
label(`for`:=levelId, style:="padding-left: 5px")(text)
)
}, br,
input(`type`:="button", value:="Play!", `class`:="btn btn-primary", onclick:={ () =>
if(Model.level() > 0) {
Model.start()
goto(pageGuess)
}else{
dom.alert("Please select level!")
}
})
)
)
}
^ Is this ScalaTag code actually generating HTML that can be read by a simple web crawler with no javascript support, or is it generating Javascript that is modifying the DOM to produce divs and paragraphs and what not?
I tried reading the documentation, but for div and p there was none other than "Pattern: div: Tags.this.ConcreteHtmlTag[html.Div]"
It uses both, well at least now it does:
From the docs:
Although Scalatags was originally a HTML-String generation library, it now
ships with an additional backend that runs only on ScalaJS.
Furthermore:
The DOM backend provides an additional method .render on all Scalatags fragments, which converts the fragment into a DOM tree:
val elem = div.render
assert(elem.children.length == 0)
elem.appendChild(p(1, "wtf", "bbq").render)
assert(elem.children.length == 1)
val pElem = elem.children(0).asInstanceOf[Paragraph]
assert(pElem.childNodes.length == 3)
assert(pElem.textContent == "1wtfbbq")
As you can see, you can manipulate DOM elements directly, calling standard DOM APIs like .children, .appendChild, etc.
As you can see, you can manipulate DOM elements directly, calling standard DOM APIs like .children, .appendChild, etc. Which as you know are Javascript!

Convert text prediction script [Markov Chain] from javascript to python

i've been trying the last couple days to convert this js script to python code.
My implementation (blindfull cp mostly, some minor fixes here and there) so far:
import random
class markov:
memory = {}
separator = ' '
order = 2
def getInitial(self):
ret = []
for i in range(0, self.order, 1):
ret.append('')
return ret
def breakText(self, txt, cb):
parts = txt.split(self.separator)
prev = self.getInitial()
def step(self):
cb(prev, self.next)
prev.shift()#Javascript function.
prev.append(self.next)
#parts.forEach(step) # - step is the function above.
cb(prev, '')
def learn(self, txt):
mem = self.memory
def learnPart(key, value):
if not mem[key]:
mem[key] = []
mem[key] = value
return mem
self.breakText(txt, learnPart)
def step(self, state, ret):
nextAvailable = self.memory[state] or ['']
self.next = nextAvailable[random.choice(nextAvailable.keys())]
if not self.next:
return ret
ret.append(next)
nextState = state.slice(1)
return self.step(nextState, ret)
def ask(self, seed):
if not seed:
seed = self.genInitial()
seed = seed + self.step(seed, []).join(self.separator)
return seed
Issues:
I have absolutely no knowledge of javascript.
When i try to "learn" some text to a "markov" class object [e.g.: a=markov(); a.learn("sdfg");] i get the following error: "TypeError: unhashable type: 'list'", for the "mem" dictionary at the "learnPart" function, member of the "learn" function.
So my question so far is why does this exception [TypeError for a list object, falsely referring to a dictionary object (which is hashable)] occur?
thanks in advance for any suggestions, directions, points, help in general :D
Guy who wrote the article speaking. Glad you found it useful! Now, my first implementation of a Markov chain was actually in Python, so this answer will focus on how to write it in a more Pythonic way. I'll show how to go about making an order-2 Markov chain, since they're easy to talk about, but you can of course make it order-N with some modifications.
Data Structures
In js, the two prominent data structures are the generic object and the array (which is an extension to the generic object). In Python however, you have other options for more finely-grained control. Here're the major differences in the two implementations:
A state in our chain is really a tuple - an immutable, ordered structure, with a fixed amount of elements. We always want n elements (in this case, n=2) and their order has meaning.
Manipulating the memory will be easier if we use a defaultdict wrapping a list, so we can skip the "checking if a state doesn't exist, and then doing X", and instead just do X.
So, we stick a from collections import defaultdict at the top and change how markov.memory is defined:
memory = defaultdict(list)
Now we change markov.getInitial to return a tuple (remember this explains an order-2 chain):
def getInitial(self):
return ('', '')
(if you want to expand it further, you can use a really neat Python trick: tuple([''] * 2) will return the same thing. Instead of empty strings, you can use None)
We'll get to changing what uses genInitial in a bit.
Yield and iteration
A strong concept which doesn't exist in js (yet) but does exist in Python is the yield operator (see this question for great explanations).
Another feature of Python is its generic for loop. You can go over nearly anything quite easily, including generators (functions which use yield). Combining the two, and we can redefine breakText:
def breakText(self, txt):
#our very own (ε,ε)
prev = self.getInitial()
for word in txt.split(self.separator):
yield prev, word
#will be explained in the next paragraph
prev = (prev[1], word)
#end-of-sentence, prev->ε
yield prev, ''
The magic part above, prev = (prev[1], word) can be explained best by example:
>>> a = (0, 1)
>>> a
(0, 1)
>>> a = (a[1], 2)
>>> a
(1, 2)
That's how we advance through the word list. And now we move up to what uses breakText, to the redefinition of markov.learn:
def learn(self, txt):
for part in self.breakText(txt):
key = part[0]
value = part[1]
self.memory[key].append(value)
Because our memory is a defaultdict, we don't have to worry about the key not existing.
A pee break on the side of the road
OK, we have half of the chain implemented, time to see it in action! What we have so far:
from collections import defaultdict
class Markov:
memory = defaultdict(list)
separator = ' '
def learn(self, txt):
for part in self.breakText(txt):
key = part[0]
value = part[1]
self.memory[key].append(value)
def breakText(self, txt):
#our very own (ε,ε)
prev = self.getInitial()
for word in txt.split(self.separator):
yield prev, word
prev = (prev[1], word)
#end-of-sentence, prev->ε
yield (prev, '')
def getInitial(self):
return ('', '')
(I changed the class name from markov to Markov because I cringe every time a class begins with a lowercase letter). I saved it as brain.py and loaded up Python.
>>> import brain
>>> bob = brain.Markov()
>>> bob.learn('Mary had a little lamb')
>>> bob.memory
defaultdict(<class 'list'>, {('had', 'a'): ['little'], ('Mary', 'had'): ['a'], ('', ''): ['Mary'], ('little', 'lamb'): [''], ('a', 'little'): ['lamb'], ('', 'Mary'): ['had']})
Success! Let's look at the result more carefully, to see that we got it right:
{ ('', ''): ['Mary'],
('', 'Mary'): ['had'],
('Mary', 'had'): ['a'],
('a', 'little'): ['lamb'],
('had', 'a'): ['little'],
('little', 'lamb'): ['']}
zips up Ready to drive on? We still have to use this chain!
Changing the step function
We've already met what we need to remake step. We have the defaultdict, so we can use random.choice right away, and I can cheat a bit because I know the order of the chain. We can also get rid of the recursion (with some sorrow), if we see it as a function which takes a single step through the chain (my bad in the original article - a badly named function).
def step(self, state):
choice = random.choice(self.memory[state] or [''])
if not choice:
return None
nextState = (state[1], choice)
return choice, nextState
I regretfully added the or [''] because random.choice moans about empty lists. Finally, we move a larger portion of the logic to ask (the actual construction of the sentence):
def ask(self, seed=False):
ret = []
if not seed:
seed = self.getInitial()
while True:
link = self.step(seed)
if link is None:
break
ret.append(link[0])
seed = link[1]
return self.separator.join(ret)
Yes, a bit yucky. We could have given step a better name and made it a generator, but I'm late for a meeting with my pregnant wife who's about to give birth to a baby who left the stove on fire in my car that's being towed! I better hurry!
The grand finale
But first, a talk with bob:
from collections import defaultdict
import random
class Markov:
memory = defaultdict(list)
separator = ' '
def learn(self, txt):
for part in self.breakText(txt):
key = part[0]
value = part[1]
self.memory[key].append(value)
def ask(self, seed=False):
ret = []
if not seed:
seed = self.getInitial()
while True:
link = self.step(seed)
if link is None:
break
ret.append(link[0])
seed = link[1]
return self.separator.join(ret)
def breakText(self, txt):
#our very own (ε,ε)
prev = self.getInitial()
for word in txt.split(self.separator):
yield prev, word
prev = (prev[1], word)
#end-of-sentence, prev->ε
yield (prev, '')
def step(self, state):
choice = random.choice(self.memory[state] or [''])
if not choice:
return None
nextState = (state[1], choice)
return choice, nextState
def getInitial(self):
return ('', '')
And loading it up:
>>> import brain
>>> bob = brain.Markov()
>>> bob.learn('Mary had a little lamb')
>>> bob.ask()
'Mary had a little lamb'
>>> bob.learn('Mary had a giant crab')
>>> bob.ask(('Mary', 'had'))
'a giant crab'
There is, of course, room for improvement and expanding on the concept. But it wouldn't be any fun if if I just gave you the answer.
Hopefully this will still help after 4 months.
The complex answer
The issue here is that learnPart is trying to use the return value of getInitial, which is a list, as a key to a dictionary. Lists are mutable, and hence not hashable, which means they can't be used as keys to a dictionary.
You could try adding this line to learnPart:
def learnPart(key, value):
key = tuple(key) #<-----Try adding this line
if not mem[key]:
mem[key] = []
mem[key] = value
return mem
But I do not think that will solve all the problems.
The simple answer
There are plenty of Markov Chain implementations written in Python out there. A quick search on Github yielded 168 projects:
https://github.com/search?l=Python&q=markov+chain
I kind of made a simplified version of the code:
import re
class Brain():
H = ''
def learn(self, txt):
self.H = txt
def ask(self,ask):
H=self.H
ask = re.compile(r"%s(.*)"%(ask),re.I|re.DOTALL)
m = ask.search(H)
print m.group(1)
Here's the execution:
>>> import brain
>>> bob = brain.Brain()
>>> bob.learn('Mary had a little lamb' )
>>> bob.ask('Mary had')
'a little lamb'
I agree that this isn't exactly a Markov chain algorithm.But it has a few advantages:
i. You can supply ask() with raw text as shown above.
ii. It has a fewer lines of code.
iii. And hopefully, it is easier to understand.

Categories

Resources