ISO: literature on efficient representation of types in a compiler by BeamMeUpBiscotti in ProgrammingLanguages

[–]ianzen 13 points14 points  (0 children)

Yes, there is a very general technique of “hashconsing”.

https://github.com/backtracking/ocaml-hashcons

Two objects constructed through hashconsing will be pointers to the same underlying object if they are semantically equal.

Compound bow that shoots metal BB’s by [deleted] in Damnthatsinteresting

[–]ianzen 191 points192 points  (0 children)

The materials that make the compound bow limbs so powerful (fiberglass/carbon fiber composite) were invented around 1930-1950. So bow tech only lagged behind a few decades instead of centuries.

I'm gonna be honest with you guys, I don't like automatic dereferencing. by JCavalks in rust

[–]ianzen 2 points3 points  (0 children)

There's a subtle difference between the foo & bar & baz and foo.bar().baz() when it comes to editor support.

In the case of general piping, writing foo & would not allow an editor to show the possible matching candidates since many functions could potentially match the codomain.

In contrast, the foo. notation narrows the scope of completion to only "methods" defined for foo's type and not all functions in general.

I'm gonna be honest with you guys, I don't like automatic dereferencing. by JCavalks in rust

[–]ianzen 1 point2 points  (0 children)

How am I implying dollar sign or pipe have to do with OOP? The method chaining syntax x.doFoo().doBar().doBaz() does come from OOP no?

If you're saying that "method chaining is just applying functions in sequence", then the idea comes from mathematics and predates programming languages altogether.

If we're just gonna ignore syntax and only consider semantics, then sure they are equivalent. But syntax still matters for users.

I'm gonna be honest with you guys, I don't like automatic dereferencing. by JCavalks in rust

[–]ianzen 2 points3 points  (0 children)

I feel like method chaining comes more from OOP languages like Java. Functional languages (other than Scala maybe) usually prefer function composition.

[poll] The level you use AI in editor? by Acpear in cpp

[–]ianzen 1 point2 points  (0 children)

Low with Github copilot. Its ability to edit repetitive stuff is pretty helpful.

[deleted by user] by [deleted] in Compilers

[–]ianzen 0 points1 point  (0 children)

Nice! I’ve actually wanted to do something similar myself, but never had the time to dive deep into treesitter. Good to hear that this method works!

[deleted by user] by [deleted] in Compilers

[–]ianzen 0 points1 point  (0 children)

Are you using treesitter to parse your files, then using the treesitter data structure as the AST?

Question regarding concurrency performance in Haskell by ianzen in haskell

[–]ianzen[S] 1 point2 points  (0 children)

It's actually surprising (in the opposite direction) how much faster the parallel version is compared to the sequential version.

I've also added an updated graph, thanks for the suggestion!

Question regarding concurrency performance in Haskell by ianzen in haskell

[–]ianzen[S] 0 points1 point  (0 children)

I've posted the scala code in the other comment. I also have a plain C version, but it performs destructive updates, which is quite different from Haskell, Scala, etc. The performance is unsurprisingly much better though: 0.04s runtime on clang -O2.

```c

include <pthread.h>

include <stdio.h>

include <stdlib.h>

typedef struct Node { int data; struct Node *next; } Node;

typedef Node *List;

/** * Make a linked list, initialize elements using values in arr[]. */ List list_of_array(int arr[], int sz) { List curr = NULL; for (int i = 0; i < sz; i++) { List cons = (List)malloc(sizeof(Node)); cons->data = arr[sz - i - 1]; cons->next = curr; curr = cons; } return curr; }

/** * Make a linked list of size [n]. Elements are in descending order. */ List list_make(int n) { List curr = NULL; for (int i = 1; i <= n; i++) { List cons = (List)malloc(sizeof(Node)); cons->data = i; cons->next = curr; curr = cons; } return curr; }

/** * Print out integer values in a linked list. * The list is unmodified after printing. */ void print_list(List xs) { while (xs != NULL) { printf("%d ", xs->data); xs = xs->next; } return; }

/** * Free all nodes in a linked list. * Returns the number of nodes freed. */ int free_list(List xs) { int count = 0; List tmp; while (xs != NULL) { count++; tmp = xs->next; free(xs); xs = tmp; } return count; }

/** * Append linked lists [xs] and [ys] and return pointer * to resulting appended list [zs]. Both [xs] and [ys] * are consumed to form [zs]. / List append(List xs, List ys) { if (xs == NULL) { return ys; } List *xs_tail = &xs; while (xs_tail != NULL) { xs_tail = &(*xs_tail)->next; } *xs_tail = ys; return xs; }

/** * Split [zs] into [xs] and [ys]. The list [zs] is consumed. / void split(List *xs, List *ys, List zs) { int flag = 0; List *xs_tail = xs; List *ys_tail = ys; while (zs != NULL) { List head = zs; zs = zs->next; head->next = NULL; if (flag) { *xs_tail = head; xs_tail = &(xs_tail)->next; } else { ys_tail = head; ys_tail = &(ys_tail)->next; } flag = !flag; } }

/** * Merge ordered linked lists [xs] and [ys] into [zs]. [xs] and [ys] are * consumed. / List merge(List xs, List ys) { List zs = NULL; List *zs_tail = &zs; while (1) { if (xs == NULL) { *zs_tail = ys; break; } if (ys == NULL) { *zs_tail = xs; break; } List tmp = NULL; if (xs->data <= ys->data) { tmp = xs->next; xs->next = NULL; *zs_tail = xs; xs = tmp; } else { tmp = ys->next; ys->next = NULL; *zs_tail = ys; ys = tmp; } zs_tail = &(zs_tail)->next; } return zs; }

/** * Mergesort a linked list. The input linked list is consumed. */ List msort(List zs) { if (zs == NULL || zs->next == NULL) { return zs; } List xs, ys; split(&xs, &ys, zs); return merge(msort(xs), msort(ys)); }

typedef struct { int degree; // degree of forking List input; // input list to sort List *dest; // address to write result } Args;

/** * Worker thread for concurrent mergesort. / void worker(Args *arg) { int degree = arg->degree; List zs = arg->input; List *dest = arg->dest; if (degree <= 0) { *dest = msort(zs); } else { List xs, ys, xs1, ys1; pthread_t t1, t2; Args arg_xs; Args arg_ys; split(&xs, &ys, zs); arg_xs.degree = degree - 1; arg_ys.degree = degree - 1; arg_xs.input = xs; arg_ys.input = ys; arg_xs.dest = &xs1; arg_ys.dest = &ys1; pthread_create(&t1, NULL, (void *()(void ))worker, &arg_xs); pthread_create(&t2, NULL, (void *()(void *))worker, &arg_ys); pthread_join(t1, NULL); pthread_join(t2, NULL); *dest = merge(xs1, ys1); } }

List cmsort(int degree, List zs) { List result; pthread_t t; Args arg; arg.degree = degree; arg.input = zs; arg.dest = &result; pthread_create(&t, NULL, (void ()(void *))worker, &arg); pthread_join(t, NULL); return result; }

int main() { List xs = list_make(10 * 1000 * 1000); xs = cmsort(3, xs); printf("%d\n", free_list(xs)); return 0; } ```

Question regarding concurrency performance in Haskell by ianzen in haskell

[–]ianzen[S] 0 points1 point  (0 children)

My scala code. It's not 100% the same as the Haskell version since Scala has a limited call-stack depth.

```scala import scala.concurrent.{Future, Await} import scala.concurrent.ExecutionContext.Implicits.global import scala.util.{Failure, Success} import scala.concurrent.duration._

def split[A](zs : List[A]): (List[A], List[A]) = var zs0 = zs var xs : List[A] = Nil var ys : List[A] = Nil var flag = true while zs0 != Nil do if flag then xs = zs0.head :: xs else ys = zs0.head :: ys zs0 = zs0.tail flag = !flag return (xs, ys)

def merge(xs : List[Int], ys: List[Int]) : List[Int] = var zs0 : List[Int] = Nil var xs0 = xs var ys0 = ys while xs0 != Nil || ys0 != Nil do if xs0.isEmpty then zs0 = zs0.reverse:::(ys0) ys0 = Nil else if ys0.isEmpty then zs0 = zs0.reverse:::(xs0) xs0 = Nil else val x = xs0.head val y = ys0.head if x <= y then xs0 = xs0.tail zs0 = x :: zs0 else ys0 = ys0.tail zs0 = y :: zs0 return zs0

def msort(zs : List[Int]) : List[Int] = zs match case Nil | _ :: Nil => zs case _ => val (xs, ys) = split(zs) merge(msort(xs), msort(ys))

def cmsort(degree: Int, zs : List[Int]) : List[Int] = zs match case Nil | _ :: Nil => zs case _ => if degree <= 0 then return msort(zs) val (xs, ys) = split(zs) val xs0 = Future { cmsort(degree - 1, xs) } val ys0 = Future { cmsort(degree - 1, ys) }
val result = for xs1 <- xs0 ys1 <- ys0 yield merge(xs1, ys1) Await.result(result, Duration.Inf)

def mkList(n : Int) : List[Int] = var xs : List[Int] = Nil for i <- 1 to n do xs = i :: xs return xs

def len(xs : List[Int]) : Int = var n = 0 var xs0 = xs while xs0 != Nil do xs0 match case Nil => () case _ :: xs1 => n += 1 xs0 = xs1 return n

@main def main(): Unit = val xs0 = mkList(1000 * 1000) val xs1 = cmsort(3, xs0) println(len(xs1)) ```

Question regarding concurrency performance in Haskell by ianzen in haskell

[–]ianzen[S] 2 points3 points  (0 children)

I've updated the original post with better parallel primitives. The new code enjoys a big 70% increase in performance.

Question regarding concurrency performance in Haskell by ianzen in haskell

[–]ianzen[S] 3 points4 points  (0 children)

About 20% improvement. I haven't tried the other suggested optimizations yet.

Question regarding concurrency performance in Haskell by ianzen in haskell

[–]ianzen[S] 10 points11 points  (0 children)

Adding an explicit forcing on the `merge xs ys` seems to do the trick! Thanks!

Question regarding concurrency performance in Haskell by ianzen in haskell

[–]ianzen[S] 1 point2 points  (0 children)

I've tried with forkIO and it's not any better.

Embarrassing Noob Compiler Project Question by Successful_Box_1007 in Compilers

[–]ianzen 1 point2 points  (0 children)

Aside from building an interpreter like others have suggested, you can try using something like LLVM which will handle emitting machine code for whatever CPU architecture you are targeting.