carp-lang / carp Goto Github PK
View Code? Open in Web Editor NEWA statically typed lisp, without a GC, for real-time applications.
License: Apache License 2.0
A statically typed lisp, without a GC, for real-time applications.
License: Apache License 2.0
Gitter discussion suggests that possible solution could be printf macro.
Hi, I've being poking around with carp in repl, but unfortunately I don't seem to get it to produce output
Welcome to Carp 0.2.0
This is free software with ABSOLUTELY NO WARRANTY.
Evaluate (help) for more information.
鲮 (use Array)
鲮
鲮 (defn map [f xs]
(let [ys []]
(do
(for [i 0 (count &xs)]
(aset! &ys i (f (nth &xs i))))
ys)))
鲮 (type map)
map : (λ [(λ [&r18] r15), (Array r18)] (Array r15))
鲮 (c map)
Found unresolved generic type '(λ [(λ [&r12] r15), (Array r12)] (Array r15))' at line 1, column 0 in 'REPL', can't print resulting code.
Found unresolved generic type '(λ [(Array r15)] ())' at unkown line, unknown column in 'Array.delete__UNSOLVED_VARIABLE template', can't print resulting code.
Found unresolved generic type '(λ [(Array r15)] ())' at unkown line, unknown column in 'Array.delete__UNSOLVED_VARIABLE template', can't print resulting code.
鲮
I suspect it's due to f
being polymorphic, is that a limitation or am I overlooking something ?
This is a tracking issue for a known bug in Carp: when a function uses Arrays, but does not generate them, no typedef is emitted. This leads to errors in the C compiler. For an example see the following function:
(defn accumulate [arr]
(let [acc 0]
(do
(for [i 0 (count arr)]
(set! &acc (+ acc @(Array.nth arr i))))
arr)))
It can be fixed currently by defining a bogus function that generates an array, for instance:
(defn bogus []
[0.0])
Cheers
The String module is probably lacking a lot of useful functions commonly found in other standard libraries. Let's add them!
I've run and rebuilt the example in the README a bunch of times, but the answer is always 77.
Why would that be?
By request I made a binary release of the current compiler (get it here).
It would be great if we had a shell script that copied the correct files to a folder and compressed the whole thing, removing the need for human intervention as much as possible.
What type system are you planning on using. will you support algebraic data types, typeclasses and monads?
Is there a reason why fern bodies don’t implicitly wrap the body with a do?
My work on #24 has left some users ( @daveyarwood ) unable to build, whereas @eriksvedang is still able to build.
Opening issue to track progress.
I am working on setting up travis-ci for mac, I have #53 waiting which adds travis linux builds.
As of #37 we now have contains?
, array-contains?
, string-contains?
.
I see a few ways of handling this:
contains?
method test it's argument and dispatch to list-contains?
, array-contains?
, string-contains?
- this works for builtin types but cannot be user extended.contains
operate via an interface that supports all the builtin types that can also be extended - I am unsure if Carp currently has the capability for this.What are your thoughts?
The dont-remove-this-file
file can be replaced by something more elegant, a simple .gitignore
in the directory with the contents:
*
!.gitignore
will keep the directory empty at all times, but still in git.
I've been pondering a good way to annotate top level forms with documentation and (optional) type signatures.
Here are some suggestion:
A doc
and sig
command.
(doc average "Calculates the average value of an Array of double:s.")
(sig average (λ [(Array Double)] Double))
(defn average [nums]
<implementation>)
Reader macros.
^doc "Calculates the average value of an Array of double:s."
^sig (λ [(Array Double)] Double)
(defn average [nums]
<implementation>)
They would probably expand to something like this:
(doc "Calculates the average value of an Array of double:s."
(sig (λ [(Array Double)] Double)
(defn average [nums]
<implementation>)))
More flexible versions of def
/defn
.
(defn average [nums]
(λ [(Array Double)] Double)
"Calculates the average value of an Array of double:s."
<implementation>)
I think all the versions above are passable but not immediately attractive. Does anyone have other suggestions to take into account?
Can't understand type when registering '+'
Can't understand type when registering '-'
Can't understand type when registering '*'
Can't understand type when registering '/'
Can't understand type when registering '<'
Can't understand type when registering '>'
Can't understand type when registering '='
Can't understand type when registering 'mod'
Can't understand type when registering 'seed'
Can't understand type when registering 'random'
Can't understand type when registering 'random-between'
Can't understand type when registering 'str'
Can't understand type when registering 'from-string'
Can't understand type when registering 'mask'
Can't understand type when registering 'inc'
Can't understand type when registering 'dec'
Can't understand type when registering 'copy'
[TYPE ERROR] Trying to refer to an undefined symbol 'for' at line 9, column 9.
Can't understand type when registering '='
Can't understand type when registering 'copy'
Can't understand type when registering 'count'
Can't understand type when registering 'duplicate'
Can't understand type when registering 'cstr'
Can't understand type when registering 'str'
Can't understand type when registering 'chars'
[PARSE ERROR] "(source)" (line 9, column 10):
unexpected "'"
expecting "&", "@", "(", "[", digit, "-", "\"", "\\", letter or ")"
The REPL itself works. But I only get useful output for strings:
string _0 = strdup("Test");
Else I get nothing or error messages.
Hi - I just discovered Carp and it looks awesome. I'm itching to try it out!
I just cloned this repo and ran cmake .
, and it appeared to execute successfully:
$ cmake .
-- The C compiler identification is AppleClang 6.0.0.6000057
-- The CXX compiler identification is AppleClang 6.0.0.6000057
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/Carp
This created a bin/
folder with a few files in it:
$ ls bin
carp carp-inferior carp.bat
NOTE: I moved /tmp/Carp
to ~/Code/Carp
at this point:
$ ls ~/Code/Carp/bin
carp carp-inferior carp.bat
However, when I try to run carp
, I get an error about bin/carp-repl
not existing:
$ bin/carp
rlwrap: error: Cannot execute /Users/dave/Code/Carp/bin/carp-repl: No such file or directory
I get the same result when trying to run the example .carp
files, and after including carp
in my PATH
.
Now when we have interfaces it should be possible to rewrite some (most) of the Array functions using plain carp. This will clean up the compiler and make it less likely that a memory error slips in through the template generated C code.
When defining variables that clash with typenames, we get spurious error from the C compiler, most notably when naming things string
or pattern
—which might be desirable names.
Minimum viable example:
(def string "hi")
(defn main []
(IO.println string))
Please note that while string
and pattern
are most certainly the most notable examples, this also works with any other C type, e.g. uint8_t
.
I guess this could be fixed by mangling variable names as well?
Cheers
When trying to compile this—faulty—program:
(use Array)
(defn add-int [&x &y] (Int.+ (Int.copy x) (Int.copy y)))
(defn main []
(do (println (Array.reduce add-int 0 [1 2 3 4 5]))))
the compiler dies with the error carp: src/Obj.hs:433:29-104: Non-exhaustive patterns in lambda
. The line is envWithArgs
, where a pattern match occurs in a lambda that is not exhaustive.
The line of the above program that triggers the bug is (defn add-int [&x &y] (Int.+ (Int.copy x) (Int.copy y)))
. Typing this in a REPL will also cause a crash.
Cheers
Pascal strings are length-prefixed strings in contrast to Zero-terminated C strings.
https://en.wikipedia.org/wiki/String_(computer_science)#Length-prefixed
They have many advantages over C strings and no drawbacks [1] when you have something like std::string_view or Rust's slices.
[1] One might still say the extra memory overhead for the length field is a problem.
hi,
The first feature on the list: "Automatic and deterministic memory management".
Could this be elaborated a bit more extensively? What are your strategies? What does Carp different then all the other languages that use either manual or automatic memory management?
Thanks
From what I can tell by playing with it going through docs it does not seem like there are closures or am I missing something ?
Can be problematic for different c-compilers.
Example, the pi character were problematic for avr-gcc.
Would you like to add more error handling for return values from functions like the following?
looking at src/bytecode.c I see
// 'a' push lambda <literal>
// 'c' call <argcount>
// 'd' def <literal>
// 'e' discard
// 'g' catch
// 'i' jump if false
// 'j' jump (no matter what)
// 'l' push <literal>
// 'n' not
// 'o' do
// 'p' push nil
// 'r' reset!
// 't' let
// 'u' end of function (process->function_trace_pos--)
// 'v' pop let scope
// 'x' direct lookup
// 'y' lookup <literal>
// 'q' stop
and then throughout the code
bytecodeObj->bytecode[*position] = 'a';
would it be beneficial to refactor this?
we could represent the bytecode as an enum, that way instead of using the literal 'a' you could use lambda
(we could even set the enum values to match the letters, so it is still printable).
we could instead use defines.
This could also just be busy work, what are your thoughts?
Struggled through a LOT of setup/config issues when putting Carp into a Docker image. (I have the Dockerfiles--both the carp image and the haskell one I build that it depends on--in a public Git repo if anyone wants to tell me if/how my config is borked--I'm not really a Haskeller so I'm very ready to admit that what I'm doing here is borked. https://bitbucket.org/TedNeward/Docker.git/carp and https://bitbucket.org/TedNeward/Docker.git/haskell, respectively.)
When I got everything to build, though, and try to run Carp against one of the examples ("basics.carp"), I get an error: hGetContents: invalid argument (invalid byte sequence). No idea how to fix this.
All I really want to do is play with Carp for a while, not build it from source--if there's a working binaries image I can grab, I'd do that in a heartbeat, but I don't see one anywhere....?
The following code
;; Test
(use IO)
(use Int)
(use String)
(def myvariable (the Int 5))
(defn main []
(println ( ref(Int.str myvariable))))
gives
./out/main.c:196:18: error: initializer element is not a compile-time constant
int myvariable = _5;
Can you support Readable / Sweet syntax by @david-a-wheeler
http://readable.sourceforge.net/
http://www.dwheeler.com/readable/
http://www.dwheeler.com/readable/sweet-expressions.html
IO.println
is rather coy about what type it expects.
(defn main [] (IO.println "foo")) ; OK
(defn main [] (IO.println (Int.str 42))) ; ERROR: (Int.str 42): String, expected &String
(defn main [] (IO.println &(Int.str 42))) ; OK
(defn main [] (IO.println &"foo")) ; ERROR: (ref "foo"): &String, expected String
So which is it?!
in rust and other languages, have support for enumerations. which allows for creating types that
must match some planned types.
some syntax suggestions
no extra data -- nil or unit value
not sure what might be used other wise.
``
(defenum months [ january nil
febuary nil
march nil
april nil ]
;dont know what you guys use for generics
(defenum option [ Some T
None nil ]
``
#:~/p/p/carp|master✓
➤ bin/carp
λ> (load-lisp "examples/spin.carp")
ERROR: Failed to open dylib: "libglfw.so.3"
----------------------------------------------------------------
3 load-dylib gl.carp 9:0
2 load-lisp core.carp 365:0
1 No meta data.
0 load-lisp repl 1:0
----------------------------------------------------------------
λ>
#:~/p/p/carp|master✓
➤ whereis libglfw.so.3
libglfw.so: /usr/lib/libglfw.so /usr/lib/libglfw.so.2 /usr/local/lib/libglfw.so /usr/local/lib/libglfw.so.3
I'm not very experienced building on Linux. Is there something I'm missing?
https://en.wikipedia.org/wiki/End-of-Transmission_character
pressing ctrl + d in the repl creates an infinite sequence of empty function calls.
I think the expected behaviour is to exit the repl.
At least, that's how its referenced in preludeModules and it would be consistant with the other modules in core.
Not a problem if you're on a case-insensitive filesystem, I guess...
The functions "exit" and "printf" do not belong to the list of async-signal-safe functions.
I guess that a different program design will be needed for your function "signal_handler".
Issue: It's not possible to encode all valid Lisp identifiers, type names differentiating overloaded functions, namespaces directly in C because C identifiers are very strict, so Carp is creating its own name mangling strategy.
Suggestion: adopt the C++ name mangling scheme.
The C++ name mangling strategy has two advantages: already exists and is understood by many tools.
Even Rust has adopted it https://github.com/rust-lang/rust/blob/76affa5d6f5d1b8c3afcd4e0c6bbaee1fb0daeb4/src/librustc_trans/back/symbol_names.rs#L358
According to the compiler, this is a valid Carp program:
(defn main []
@"Hi there!")
Compiling it will result in the following C code:
int main() {
string _4 = "Hi there!";
string *_4_ref = &_4;
string _5 = String_copy(_4_ref);
return _5;
}
The generated C code tries to return a string
/char *
from a function declared int
. The C compiler will probably complain, although it might only be a warning.
A naive idea to fix this problem: introduce main
as a fix point to the type checker (i.e. make it common knowledge that main
is always of type [] -> Int
. This way at least the type checker would fail, which is better than having the C compiler handle it.
Cheers
Can you license this as a combination of:
for the compiler and
for the libraries.
Also it might be an idea to triple license it using ASL 2.0, Boost, either MIT or 2-BSD for compiler and standard library.
All the core registered c functions of carp are defined in core.h. That means it is not possible to compile a program which only uses parts of core.h by using the --no-core compiler flag and then loading individual carp modules.
A possible solution could be to split core.h into different modules, i.e. int_core.h for functions registered in Int.carp and so on. (Somehow the necessary stdlib headers would need to be included also) What are some good ways achieve a modular system?
@hellerve has added a whole lot of math functions to the Double module. The Float module is way behind though, and there are also probably a few useful functions left to add for all the different math modules (Int / Long / Float / Double).
I forked your repo and managed to add some minor fixes to get it compiling under Linux including the spin demo @ paines@fd4c1bc. Unfortunately I do not understand how to create a pull request !
It would be a idea to move to own github org.
The mkdir and touch implementations in core.karp just concatenate the given name into a shell expression. Things like (mkdir "dir; malicious_program")
will therefore not do the expected thing; this is a problem if user input is directly given to mkdir and/or touch.
I'd expect not to have to quote input when giving it to those functions.
Fix would be to use fork/execlp not sure how feasible that is from lisp?
Have you considered Carp as a first unikernel friendly LISP? Unikernel applications have to be fast to restart, have low memory profile and usually they are "single threade". It seems like Carp can provide it all.
Links for research
https://github.com/rumpkernel/rumprun/
https://github.com/solo-io/unik
LISPs like Clojure can't target WebAssembly because they need GC and WebAssembly still lacks it.
Carp can use LLVM to compile into WebAssembly.
Not sure about that one but You might be interested since Carp also has type inference
Since we have a new and shiny benchmarking module it would be great with some examples of how fast (or slow) different things are in Carp. Preferably the examples should be similar to what other languages often do, making it easier to compare between languages.
It would also be interesting to compare different approaches within Carp, for example direct mutation compared to using the updating-functions, and similar.
Since we have a new and shiny testing library it would be awesome if all the old "tests" in the example folder would be moved to the 'test' folder and converted to using the library instead of just dumping a bunch of text to stdout. I'll do this eventually but if anyone wants to start the job, please go ahead. I can assist with guidance.
Looking at the implementation for obj_new
we see
Obj *obj_new(char tag) {
Obj *o = malloc(sizeof(Obj));
o->prev = obj_latest;
o->alive = false;
o->given_to_ffi = false;
o->tag = tag;
o->meta = NULL;
obj_latest = o;
obj_total++;
if(LOG_ALLOCS) {
printf("alloc %p %c\n", o, o->tag);
}
return o;
}
a call to malloc
can fail
I would like to add some error handling here, if that suits you.
How would you like errors of this nature to be handled?
I am happy to just print error and exit the program (probably something stronger than an assert - as asserts can be compiled out).
Have you considering acquiring clojure :keywords
and maps
? Comaprision by the pointer would produce a very efficient result in map lookups
I am trying to write a matrix library. Here is the code so far:
(load "Array.carp")
(load "Vector.carp")
(defmodule Matrix
(deftype MatrixFlat [rows Int, cols Int, data VectorN.VN])
(defn init [r c data]
(if (Int.= (* r c) (Array.count &data))
(MatrixFlat.init r c (VectorN.VN.init (* r c) data))
(let [zz 0.0
data1 (Array.replicate (Int.* r c) &zz)]
(MatrixFlat.init r c (VectorN.VN.init (Int.* r c) data1)))))
(defn get [m r c]
(let [data (VectorN.VN.v (MatrixFlat.data m))
idx1 (+ (* (MatrixFlat.cols m) r) c)
idx (Int.min (Int.dec (* (MatrixFlat.rows m) (MatrixFlat.cols m)))
idx1)]
@(Array.nth data idx)))
(defn set [m r c val]
(let [data (VectorN.VN.v (MatrixFlat.data m))
idx1 (+ (* (MatrixFlat.cols m) r) c)
idx (Int.min (Int.dec (* (MatrixFlat.rows m) (MatrixFlat.cols m)))
idx1)]
(Array.aset! data idx val)))
(defn to-string [o]
(string-join @"Matrix(rows = " (Int.str (MatrixFlat.rows o)) @", cols = "
(Int.str (MatrixFlat.cols o)) @", values = "
(Array.str (VectorN.VN.v (MatrixFlat.data o))) @") "))
(defn add [m1 m2]
(MatrixFlat.init (MatrixFlat.rows m1) (MatrixFlat.cols m1)
(VectorN.add (MatrixFlat.data m1) (MatrixFlat.data m2))))
(defn sub [m1 m2]
(MatrixFlat.init (MatrixFlat.rows m1) (MatrixFlat.cols m1)
(VectorN.sub (MatrixFlat.data m1) (MatrixFlat.data m2))))
(defn mul [m a]
(MatrixFlat.init (MatrixFlat.rows m) (MatrixFlat.cols m)
(VectorN.mul (MatrixFlat.data m) a)))
(defn div [m a]
(MatrixFlat.init (MatrixFlat.rows m) (MatrixFlat.cols m)
(VectorN.div (MatrixFlat.data m) a)))
(defn matmul [m1 m2]
(let [r1 (MatrixFlat.rows &m1)
c1 (MatrixFlat.cols &m1)
r2 (MatrixFlat.rows &m2)
c2 (MatrixFlat.cols &m2)
res (init r1 c2 [])]
(do
(for [i 0 r1]
(for [j 0 c2]
(let [s 0.0]
(do
(for [k 0 r2]
(set! &s (Double.+ s
(Double.* (get &m1 i k)
(get &m2 k j)))))
(set &res i j s)))))
res)))
(defn chol [m res n]
(do
(for [i 0 n]
(for [j 0 (Int.+ i 1)]
(let [s 0.0]
(do
(for [k 0 j]
(set! &s (Double.+ s (Double.* (get res i k) (get res j k)))))
(set res i j
(if (Int.= i j)
(Double.sqrt (Double.- (get m i i) s))
(Double./ (Double.- (get m i j) s) (get res j j))))))))
@res))
(defn cholesky [m]
(let [n (MatrixFlat.rows &m)]
(chol &m &(init n n []) n)))
)
(defn main []
(let [m1 (Matrix.init 2 2 [4.0 -1.0 -1.0 4.0])
m2 (Matrix.init 3 3 [25.0 15.0 -5.0 15.0 18.0 0.0 -5.0 0.0 11.0])
m3 (Matrix.cholesky @&m2)]
(do
(Matrix.set &m1 0 0 5.0)
(IO.println &(Double.str (Matrix.get &m1 0 0)))
(IO.println &(Double.str (Matrix.get &m1 1 1)))
(IO.println &(Matrix.to-string &m1))
(IO.println &(Matrix.to-string &m2))
(IO.println &(Matrix.to-string &m3)))))
when I build this project at the REPL everything is fine (I use '(load "Matrix.carp")', then '(build)')
everything is fine. When I run 'out/a.out' I get unexpected output like:
$ out/a.out
5
4
Matrix(rows = 2, cols = 2, values = [5 -1 -1 4]
Matrix(rows = 3, cols = 3, values = [25 15 -5 15 18 0 -5 0 11]ZZZZZZZZZZZZZZZZ
Matrix(rows = 3, cols = 3, values = [5 0 0 3 3 0 -1 1 3]
I would have expected:
$ out/a.out
5
4
Matrix(rows = 2, cols = 2, values = [5 -1 -1 4])
Matrix(rows = 3, cols = 3, values = [25 15 -5 15 18 0 -5 0 11])
Matrix(rows = 3, cols = 3, values = [5 0 0 3 3 0 -1 1 3])
Can you help me find out what's wrong? Many thanks in advance.
I started working on Windows support but got stuck on the parser. It doesn't handle the lambda character λ
out-of-the box like it does on Linux / Mac. Perhaps someone who is more knowledgeable about text encoding on Windows knows what's going on?
As mentioned in #94, we need to wrap a regex library. I personally would like to wrap something that is as portable as possible. I’ve used regex.h
in the past, but that isn’t available on Windows (I believe).
Things to consider:
Any preferences/ideas are appreciated.
Cheers
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.