12 ms·
Unison Programming Language
- auggierose 5y agoSubmission inspired by https://news.ycombinator.com/item?id=27651197 https://news.ycombinator.com/item?id=27651197 , I guess
- WillDaSilva 5y agoThey mention using git to version Unison code, and point out how there'll practically never be any version conflicts because of the immutable / append-only nature of the language. Doesn't that mean that the git repository will only ever grow, and that old code will stick around forever? I hope I'm misunderstanding because that would be unfortunate if true.
- JoshTriplett 5y agoSeems like an intended design feature. That doesn't mean you have to keep all those old versions in every copy of the repository; you could always fetch only versions you need, for instance.
- teraflop 5y agoIsn't that true of any Git repository? The internal object store keeps every version of every file that has ever existed (unless you rewrite history). In practice, Git's content-addressable storage and delta compression make it work fairly well for all but the largest repositories.
- dthul 5y agoWhat I don't understand is what they do when merging two branches. If both branches introduce a function with the same name a merge conflict is inevitable, no? Or do they not support the distributed version control approach and every developer has to submit their changes to the current version of the database?
- refried_ 5y agoIt produces a name conflict, but (unlike git merge conflicts) these don't prevent any previously written code from running normally. A name conflict only needs to be resolved as a convenience to the next person to try calling the function by that name, and even that next person might not have trouble if the two new functions with the same name have different types. The person just calls the one they mean, and the type-checker uses the one with the type that fits.
- umvi 5y agoI had a really hard time wrapping my mind around this just reading the website alone. If you are in the same boat, watch the first 10 minutes of this video at 1.5x speed: https://www.youtube.com/watch?v=gCWtkvDQ2ZI https://www.youtube.com/watch?v=gCWtkvDQ2ZI and it will make so, so much more sense. ...and if you are like me you'll probably need to read this twitter thread to get the answer to your #1 question: https://twitter.com/unisonweb/status/1173942974381744134 https://twitter.com/unisonweb/status/1173942974381744134 Basically the core idea (or one of the core ideas) is instead of a function (like fib(n) which returns nth Fibonacci number) being identified by its name (fib) as is the case with most traditional languages, it's instead identified by a hash of its implementation.
- lisper 5y agoSounds like a cool idea, but how do you fix bugs in functions with lots of callers?
- acjohnson55 5y agoThe same way we do now: release a new version and tell people to migrate.
- lisper 5y agoNo, now I can just redefine the buggy function and all the callers will get the new version automatically. Having to update all callers seems like a high price to pay. Seems like the Right Answer is something like a hash of the api or the contract rather than the implementation.
- ucarion 5y agoThe (public) name of the implementation is the unique identifier of the contract in most systems, so I think your "Right Answer" is roughly the status quo?
- 5y ago
- brundolf 5y ago> Unison definitions are identified by content. Each Unison definition is some syntax tree, and by hashing this tree in a way that incorporates the hashes of all that definition's dependencies, we obtain the Unison hash which uniquely identifies that definition. Very cool core concept. Reminds me of some things Rich Hickey has said about the idea of versioning dependencies at the function level That said: I wonder if this idea would make more sense as static analysis on an existing language. It would have to be trivial to enumerate all code that might influence a function's behavior; so something totally pure like Haskell or Elm
- xpe 5y agoYes, Rich Hickey (a bit more systematic) and Joe Armstrong (a bit more scattershot) have popularized some of these ideas. I'd be very interested in learning about analagous static analysis tools for referentially transparent languages / purely functional languages with sufficiently expressive type systems. Please share what you find :)
- janjones 5y agoThere is nice blog post summing up what's cool about Unison[1] [1] https://jaredforsyth.com/posts/whats-cool-about-unison/ https://jaredforsyth.com/posts/whats-cool-about-unison/
- grawprog 5y agoThank you, that helped explain pretty well what abilities are. I felt like I was kind of starting to get what the language was about, then I hit the abilities section and I had no idea what it was talking about.
- PaulDavisThe1st 5y agoGood explanations, but I'm always a little suspicious when I see things like this: > Code is stored as a structured, type-checked tree in a database, not as text in files What does everyone think a filesystem is?
- thethimble 5y agoThere’s an important distinction between how non-unison code is stored (literally as plain text files which must be re-parsed and re-compiled every time) vs how unison code is stored (as a post-parsing data structure). The file system is in an entirely different and irrelevant layer of abstraction.
- turtletontine 5y agoI'm not totally sure what the important distinction is here. For many languages the important thing is already a post-parsing data structure, that's what any compilation output or byte code is. You obviously want to keep the raw source around as well if you're the developer. Nothing new about having separate source code and compiled formats?
- turtletontine 5y agoUpdate: I'm skimming here (https://jaredforsyth.com/posts/whats-cool-about-unison/ https://jaredforsyth.com/posts/whats-cool-about-unison/) and here (https://joshondesign.com/2012/04/09/open-letter-language-designers https://joshondesign.com/2012/04/09/open-letter-language-des...) and I see Unison is serious about not having raw text source code as the ground truth. I'm intrigued but don't totally understand yet. I'm sure this analogy is technically incorrect but: This reminds me of Smalltalk and old Lisps on mainframes shared by many researchers where the main thing was the VM image, not an object file. Though the probably kept the source code around? At a gut level getting rid of source code makes me uncomfortable but I'm ready to learn more. PS sorry for the ugly raw links I'm on my phone
- wyager 5y agoThis looks pretty well done. It doesn’t seem like a gimmick; they’ve made a lot of good choices beyond the core conceit of content-addressable code. One thing I didn’t see skimming the language reference page: is there any sort of typeclass mechanism?
- refried_ 5y agoNo, but it’s planned; probably in the form of implicit parameters.
- anka-213 5y agoIs there a fundamental limitation that would make it impossible to use a haskell-style coherent typeclass system, where the instance of a typeclass must be globally unique? My guess is yes, since that would probably forbid modifying the instance, since we would now have both the new and old copy. Unless of course we couple type class instances with the definition of the type itself (or the definition of the class) and view the type together with all its instances as a unit (as Unison does with mutually recursive functions), but that would bring on its own set of issues.
- thom 5y agoSuper interesting, I was thinking about append-only codebases very recently: https://news.ycombinator.com/item?id=27492727 https://news.ycombinator.com/item?id=27492727 The implications of this, with the right frameworks and processes, seem potentially huge.
- joe_the_user 5y agoThe thing is, the closest thing to append-only you have with ordinary programming languages APL and it's variants, where you can construct powerful functions with powerful primitives and methods for combining them. But the thing is that APL quickly becomes a "write only" language - as far as I know, the main use of APL someone sitting at a brockerage who can cobble together any algorithm on twenty minutes and often throws away the result afterwards. Which is to say, Unison is interesting because it seems to underestimate the importance of a program's code as document, as complete, coherent, human-readable, single-view, intentionally created text. Why hasn't the stream of ascii been replaced as the format of program in the last twenty years? It's a good question but the answer isn't that it's just matter of conservatism. There are several other things involved.
- acjohnson55 5y agoIt doesn't discard the text. The text, like the documentation and comments, are stored and re-rendered during editing. It's fundamentally textual. It just doesn't have to be stored as a one dimensional text stream.
- lpointal 5y agoUnison is already the name of a bidirectional files synchronization software (AFAIR developped in OCaml). https://www.cis.upenn.edu/~bcpierce/unison/ https://www.cis.upenn.edu/~bcpierce/unison/
- pvg 5y agoPreviously: https://news.ycombinator.com/item?id=22009912 https://news.ycombinator.com/item?id=22009912 https://news.ycombinator.com/item?id=9512955 https://news.ycombinator.com/item?id=9512955
- sdfjkl 5y ago> Run ucm init to initialize a Unison codebase in $HOME/.unison Ugh, this conflicts with my favorite file sync tool: https://www.cis.upenn.edu/~bcpierce/unison/ https://www.cis.upenn.edu/~bcpierce/unison/
- carapace 5y agoUnison (the file sync tool) is so awesome!
- zepearl 5y agoIt's great when it works, but different versions of <OCAML? and/or Unison?> on different hosts/VMs screw it up. I never understood the real reason why (but I never really investigated, lazy) => it's a pity.
- pchiusano 5y agoFYI you can do ‘ucm -codebase /someplace/else init’ to initialize a codebase in another directory. And then ‘ucm -codebase /somewhere/else’ to launch ucm. Also I’m not sure what Unison the file sync tool stashes in .unison or how it uses that directory but there might not be any conflict. UCM will just create a .unison/v2/unison.sqlite3 file.
- iamevn 5y agoit's really neat, I love how easy it is to search for functions by type to find what you need. The one thing I ran into (as someone who only vaguely knows haskell) is that it seems like it's impossible to write a function that takes a list of A or B as an argument and then branch on the type of each element. I can use Either but then I need to decorate each element in the list with Left/Right rather than just use their types. This is probably just not how things work in Haskell and I just need to be okay with that.
- creata 5y ago> This is probably just not how things work in Haskell and I just need to be okay with that. Yep, that's just how things work in Haskell: disjoint unions are much simpler regular unions, and they're usually what you want in the first place. I think it'd be nice if Haskell had automatic conversions between types (so a and b can be turned into Either a b implicitly, with an error if a = b) but I don't think there are any plans for that.
- JackMorgan 5y agoPerhaps are you looking for Sum Types?[0] They let you group several types into a unifying type, e.g. a Shape is a Circle, Square, or Triangle, then you can use pattern matching to have different behavior for each. This example is in F# [1] but it's almost exactly the same as it would be in Haskell. [0]https://www.schoolofhaskell.com/user/Gabriel439/sum-types https://www.schoolofhaskell.com/user/Gabriel439/sum-types [1]http://deliberate-software.com/christmas-f-number-polymorphism/ http://deliberate-software.com/christmas-f-number-polymorphi...
- sullyj3 5y agoIf you could give a concrete example of a problem to be solved, I could try to convince you that the method using Either won't actually be all that unwieldy.
- 0_gravitas 5y agoI've been semi-closely tracking this project for a while, and imo it's easily __the__ most interesting project I've seen in the sphere period. Serendipitous-ly, I came across an interview a couple weeks ago with one of the main bodies behind the project on the Corecursive podcast (from early 2019) (I think their name was Runar Bjarnason). Had no idea until it was mentioned almost offhandedly in the last few minutes!
- agbell 5y agoI think this is the episode you are talking about [1] Runar and Paul a huge inspiration! I'm not totally sold on this idea as practical, but I think it will get there and while they have a lofty goal, I certainly wouldn't bet against the pair of them. [1]: https://corecursive.com/027-abstraction-and-learning-with-runar-bjarnason/#unison-computing https://corecursive.com/027-abstraction-and-learning-with-ru...
- 0_gravitas 5y agoah yes exactly!
- jjfeiler 5y agoThe core idea here, that of hashing the ast of a function, is similar to what Maple V from Waterloo Maple Software was doing circa 1991 when I last used it.
- ajuc 5y agoThis is like maven at function level with no SNAPSHOT versions allowed :) How is recursion handled? To get a hash for a function you have to have hashes for every function it calls. Is there special "recurse" opcode? And how do you update a function implementation when you have a cycle in the callgraph?
- refried_ 5y agoYes to Maven, and good questions. Simply put, there is a special recurse opcode. When you have a cycle in the call graph, they all get hashed together as a single unit; you update them together as a single unit too.
- jiaminglimjm 5y agoProgramming language i18n.
- dthul 5y agoAn immediate caveat I came across: if you want to look at some Unison code you need a special code management tool. Take for example their base library on Github: https://github.com/unisonweb/base https://github.com/unisonweb/base The actual code lives in a sqlite file in the .unison/v2 folder. That would mean existing tools like version control and editors would need to learn about how Unison works in order to seamlessly support it. Also pulling out code into a scratch file, editing it and pushing it back into Unison's database sounds kind of annoying. Again, this could probably be solved with an editor that would make this process more seamless and feel more like editing regular code. As it currently stands it seems very cumbersome to use, mostly due to the tedious process of even just exploring a codebase, nevermind modifying it.
- zawodnaya 5y agoIn practice it's a lot less annoying than navigating a file hierarchy and looking in text files that have a lot of things other than what you're looking for. See also https://share.unison-lang.org/ https://share.unison-lang.org/ where you can look at the base library, and some (contributed?) libraries as well.
- dthul 5y agoI agree that text files might not be the best way to store code. My point was more that all of the existing tools like code editors and version control systems have been designed around the concept of files though. And instead of Unison being able to tap into the existing ecosystem of tooling, they have to rebuild custom versions. Maybe there would be a way to map a Unison codebase onto the file system and back? Edit: also worth mentioning that thanks to specialized editors you don't need to manually browse through files but you can browse your code similarly to https://share.unison-lang.org https://share.unison-lang.org if you so please. That's another plus point of the vast existing ecosystem, it already offers so much and it's a shame that Unison can't make use of it (at least for the moment).
- maddyboo 5y agoAfter reading through the Unison tour [0] with an open mind, I actually think it makes excellent use of existing tools through its "scratch files" approach [1]. The gist of it is that you can check out sections of code that you want to work on as a plain text file and you can do whatever you’d do with a text file: open it in your editor, syntax highlighting, copy/paste, whatever floats your boat. The cool part is that the “Unison codebase manager” (ucm) watches the scratch files and re-parses them whenever a file changes. I presume any syntax or type errors will be immediately shown in the ucm output. Cool, you say, but we can already do that with file watchers like `entr` and traditional languages, so why should I care? Well, it goes further. You can start a line with a > character followed by an expression and the expression will be evaluated when you save the file, printing the output inside of ucm. It’s basically a REPL that you control from your editor. Cooler still, building on this concept is the `test>` prefix which, you guessed it, creates a unit test and runs it inside ucm, showing you whether it passed or not. And as a consequence of Unison’s content-addressable nature, after a test has run for a given expression’s content hash, the result is cached and the test doesn’t need to be re-run unless the hash changes (impure functions are soooo 2020). After you’re done with the scratch file, you can run `add` in ucm to add either certain parts (I think) or all of the work you’ve done in the scratch file to the source codebase, and this includes the tests that you wrote along with their cached values (I think)! I personally find this workflow to be very compelling. To me, this approach is much akin to the source control that we do today, but it's actually aware of the context and meaning of the changes. Git, on the other hand, relies on weak heuristics to figure out what changed between versions of text-based files. I am very happy to see projects that push beyond the boundaries of the paradigms we’ve been stuck in for the past 60+ years. I also find it quite funny that Hacker News, a forum centered around startups, can often be so conservative when it comes to new technologies. [0]: https://www.unisonweb.org/docs/tour https://www.unisonweb.org/docs/tour [1]: https://www.unisonweb.org/docs/tour#unisons-interactive-scratch-files https://www.unisonweb.org/docs/tour#unisons-interactive-scra...
- barnyfried 5y agoThis is stupid
- prezjordan 5y agoStrongly encourage anyone reading this to take 20 minutes to download ucm and run through the Getting Started guide: https://www.unisonweb.org/docs/quickstart/ https://www.unisonweb.org/docs/quickstart/ Programming with a codebase manager and a scratchpad is just so much fun - I found myself hypnotized and came back an hour later with some janky min heap code. Definitely seems to scratch an itch for me.
- dang 5y agoThe past threads appear to be (others?): Unison: A Content-Addressable Programming Language - https://news.ycombinator.com/item?id=22156370 https://news.ycombinator.com/item?id=22156370 - Jan 2020 (12 comments) The Unison language - https://news.ycombinator.com/item?id=22009912 https://news.ycombinator.com/item?id=22009912 - Jan 2020 (141 comments) Unison – A statically-typed purely functional language - https://news.ycombinator.com/item?id=20807997 https://news.ycombinator.com/item?id=20807997 - Aug 2019 (25 comments) Unison Language March Update - https://news.ycombinator.com/item?id=19528189 https://news.ycombinator.com/item?id=19528189 - March 2019 (1 comment) Large-scale, well-typed edits in Unison, and reimagining version control - https://news.ycombinator.com/item?id=9708405 https://news.ycombinator.com/item?id=9708405 - June 2015 (11 comments) Unison: a next-generation programming platform - https://news.ycombinator.com/item?id=9512955 https://news.ycombinator.com/item?id=9512955 - May 2015 (128 comments)
- xpe 5y agoAlso, to go a little further back, Joe Armstrong talked about content-addressable code in a conference talk: “The Mess We're In” by Joe Armstrong at Strange Loop [video] - https://news.ycombinator.com/item?id=8342755 https://news.ycombinator.com/item?id=8342755 - Sep 2014 (77 comments)
- __david__ 5y agoThis looks like a neat idea—I can see upsides and downsides, but would have to experiment to see if one outweighs the other. One thing I didn't see in my (admittedly quick) perusal of the tutorial and faq: what is the technique to run a Unison program from the command line? Is it practical for making unix cli tools (yet)?
- sullyj3 5y agoFor the moment, you have to create a function with the appropriate IO ability, and execute using the `run` command from inside the codebase manager. I don't think there's a way to create a standalone executable just yet.
- michael-ax 5y agoI'd love to see this in c, for scheme/racket.
- deanstag 5y agoThis is really exciting. I might have missed this in the documentation, but is there any way of grouping/tagging together a set of functions, just so that conceptually similar functions can be browsed together? For traditional languages a folder/package/file performed this functionality.
- jimmux 5y agoThere is what looks like conventional namespacing.
- steve_taylor 5y ago> A friendly programming language from the future. It looks like a programming language from the present at best. A programming language from the future would have finally broken free from the prison of plain text.
- lolinder 5y agoLook a little closer. This is not a graphical programming language, but it's definitely not "plain text" either.
- steve_taylor 5y agoI looked a little closer and found this: Unison is a language in which programs are not text. That is, the source of truth for a program is not its textual representation as source code, but its structured representation as an abstract syntax tree. This document describes Unison in terms of its default (and currently, only) textual rendering into source code. Or to put it more concisely, Unison is currently a plain-text programming language.
- TuringTest 5y agoThat's akin to saying that machine code is not binary but plain text, because Assembler exists. It is more accurate to say, Unison is an AST language which nowadays happens to have just one human-readable interface, which is text.
- kvnhn 5y agoThis looks very cool! Content addressed storage is an incredibly powerful concept, and weaving it into a programming language is a compelling idea. Question for the devs: How does one deploy Unison code? After my first glance through the docs I don't have a clear picture.
- TbobbyZ 5y agowhat can you build with it?
- jbrot 5y agoVery neat project! One question about content addressed programs: how does this play out with types that are structurally equivalent but semantically distinct? For instance, assuming C definitions, an integer and a file descriptor have the same content but probably should not be treated as the same type (I wouldn’t want arithmetic to type check against file descriptors…). Another scenario: say I have a type “Foo” which contains an integer. In version 1 of my library, this integer must be even, but in version 2 I add support for odd integers, too. The Foo data type, from a content perspective, is unchanged. However, the invariants around it have changed and it’s therefore essential that it becomes a new type. Otherwise, someone might create a Foo containing an odd integer using the version 2 API and then pass it to a function from the version 1 API, resulting in bad things since the version 1 API believes Foo can never contain an odd integer.
- refried_ 5y agoThe language has "unique" types, meaning they have their own semantic meaning apart from their structure; they get a unique hash (currently implemented by adding a random salt to the hash of the structure, though it might as well be a guid). So "unique" types and "structural" types. The same question came up for terms, here: https://news.ycombinator.com/item?id=27654045 https://news.ycombinator.com/item?id=27654045
- jbrot 5y agoGlad to hear there’s a solution for this! Thanks for responding :)
- kroltan 5y agoIt looks from the other discussions that it's specifically content-addressed, not "semantic-addressed", so if your code has any redundant syntax (the given example being `x -> x + 2` vs `x -> x + 1 + 1`) it's still distinct. In that case, I guess data types can have a 0-size marker member, kind of like Rust's `PhantomData` type, that could ensure distinctness.