[HN Gopher] Unison Programming Language
___________________________________________________________________
Unison Programming Language
Author : gautamcgoel
Score : 270 points
Date : 2021-06-27 16:05 UTC (6 hours ago)
(HTM) web link (www.unisonweb.org)
(TXT) w3m dump (www.unisonweb.org)
| sdfjkl wrote:
| > 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/
| carapace wrote:
| Unison (the file sync tool) is so awesome!
| zepearl wrote:
| It'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.
| barnyfried wrote:
| This is stupid
| thom wrote:
| Super interesting, I was thinking about append-only codebases
| very recently:
|
| https://news.ycombinator.com/item?id=27492727
|
| The implications of this, with the right frameworks and
| processes, seem potentially huge.
| joe_the_user wrote:
| The 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 wrote:
| It 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.
| ajuc wrote:
| This 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_ wrote:
| Yes 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.
| umvi wrote:
| I 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
|
| 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
|
| 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.
| tgbugs wrote:
| Interesting. You can write a macro and some buffer modifying
| code to do this in elisp. But having now written up the rest of
| my response, why not just use Smalltalk?
|
| The hard part is coming up with the normalization routine which
| guarantees that (lambda (a) b a) == (lambda (b) a b) and coming
| up with the rules for statement reordering for top level and
| internal definitions so that you can identify semantically
| equivalent statements where the outcome is order invariant.
| This is critical for making the hash functions useful and I
| suspect preventing denial of service attacks on the human
| brains that have to audit the code.
|
| Being able to write a version of the code and then do the
| equivalent of creating a package.lock file to crystallize the
| hashes seems like a reasonable workflow. This probably winds up
| being easier in common lisp though since you can put the
| crystallized implementations in their own packages.
|
| You could also view this as a kind of extreme type theory where
| every function (with regular names) has the type of its
| normalized representation (compacted to a hash for sanity's
| sake) and then you can run the checker to see if the
| types/hashes have changed. If you have somewhere that keeps
| track of every hash that a function with a particular name has
| had then you could automatically refactor, or could even
| support having multiple versions of the function with the same
| name used in a program at the same time. I'm not sure how users
| would feel about having to carry around `(funcall ((with-norm-
| id '(lambda (+ a b)) f)) a b)` though ... probably just give up
| on editing the textual representation and go back to the image
| based approach of Smalltalk and Interlisp where you can hide
| the hashes.
|
| Will be interesting to see how Unison evolves.
| lisper wrote:
| Sounds like a cool idea, but how do you fix bugs in functions
| with lots of callers?
| umvi wrote:
| That's basically what the twitter thread I linked explains.
| It sounds like there is an automatic propagation mechanism
| for updating downstream callers if the type hasn't changed,
| otherwise it sounds like a manual update process.
| torginus wrote:
| Sounds like trading one set of problems for another.
| capableweb wrote:
| Welcome to software engineering where there is no golden
| bullets, only different tradeoffs :)
| aparsons wrote:
| Law of conservation of complexity
| acjohnson55 wrote:
| The same way we do now: release a new version and tell people
| to migrate.
| lisper wrote:
| No, 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 wrote:
| The (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?
| lisper wrote:
| No. The name of a function in current languages has no
| connection at all to what the function does. (What would
| be the contract for a function named 'foo'?)
| gbhn wrote:
| That's kind of the thing that makes APIs possible, right?
| It sounds to me like "what if programming were done in a
| completely flat global namespace in which abstractions,
| encapsulation, and structure were impossible."
| lisper wrote:
| No. An API specifies more than the name of the function.
| It will specify the arguments, their types, the type of
| the return value, and at least informally, what the
| function does. You can change the underlying
| implementation without changing the API. That's the whole
| point of an API. The problem with current API technology
| is that the informality of the spec of what the function
| does. That allows some aspects of the behavior of the
| function to change without triggering any warnings.
|
| By having the linker work on hashes of implementations
| you eliminate that problem but create a new problem. You
| can no longer change the behavior of the function because
| you can't change the function. That means you can't
| suddenly change behavior that some caller is counting on,
| but it also means you can't fix bugs without changes in
| the caller.
| ajuc wrote:
| Nope, according to
| https://twitter.com/unisonweb/status/1173942969726054401
|
| when you change a function implementation the system has
| to walk the callers graph backwards starting from all the
| places where the function was called updating all the
| implementations with the new hash, then callers of these
| with the new implementation and so on up to main (or
| whatever it's called).
|
| I had a chance to implement something like this in a
| system that used jbpm 3 graph language (basically process
| X version 1 called process Y version 1 and I updated
| process Y to version 2). It's nontrivial especially with
| recursion, I'm wondering how they are dealing with that.
| lamontcg wrote:
| A git-like datastore for your AST+callgraph.
| ajuc wrote:
| Let's say you have definitions like that:
| f: Nat -> Nat g: Nat -> Nat h: Nat -> Nat
| h x = g (x * 2) g x = f (x * 3) f x = x <
| 0 ? 1 : h (x / 4)
|
| And now you change f to be f x = x < 1
| ? 1 : h (x / 4)
|
| How do you do that? There's a cycle in the callgraph. In
| fact - how do you calculate a hash of a function that
| calls itself if you need its hash to calculate its hash
| :)
|
| EDIT: nevermind, recursion is a special case handled
| differently.
| dcposch wrote:
| Cool to see people thinking this big!
|
| One challenge I foresee is unintentional coupling. Say you have
| two functions:
|
| func serialize(MyRecord) ...
|
| func debugToString(MyRecord) ...
|
| Now if you ever make the mistake of having giving those the
| same implemention, then in Unison they'd be the same hash
| reference, right?
|
| Then if you want to update, say the debug print later it would
| update _all_ callsites for that hash including the ones that
| originally called serialize(). The two are no longer
| distinguishable.
| sgk284 wrote:
| The names are just pointers, and they're both pointing to the
| same definition in your example. But when you redefine one of
| those, you would point one of the names to a new definition.
|
| It's similar to how DNS can have two domains point to the
| same IP, but then you can change one of those domains point
| to a new IP.
| ajuc wrote:
| > The names are just pointers, and they're both pointing to
| the same definition in your example. But when you redefine
| one of those, you would point one of the names to a new
| definition.
|
| But how do you know which name was called where if the
| callers referenced the content hash not the name?
| milansuk wrote:
| I also think that the DNS analogy is wrong because all
| callers are hash-based. The only solution I see is to go
| through the list of all callers and manually update
| selected ones.
|
| If I understand Unison right, the names are used only on
| the developer's layer(to write code), but when you save
| code, it's all hash-based.
|
| Still, Unison got my attention.
| aparsons wrote:
| Would it not be correct for those callers to keep calling
| the old (shared) implementation?
| ajuc wrote:
| well it would be nice to have a way to update old code
| acjohnson55 wrote:
| It knows what name you intended to use, because that's in
| your source, so I'm pretty sure it isn't a problem if
| implementations converge and diverge.
| andi999 wrote:
| Cool, but why/what for?
| umvi wrote:
| I'm just as much of a novice as you, but one of the use cases
| the creators had in mind are distributed computing systems.
| For example, if you have to crunch a bunch of data in the
| cloud, you would write your data crunch function/algorithm
| (which is represented by some hash '#asdjh238ad') then spin
| up nodes to crunch data using '#asdjh238ad'. When a new node
| in a cluster comes up it can say "I don't have '#asdjh238ad'"
| and the orchestrator or one of the node's peers can send over
| a copy of it.
|
| With a traditional programming language you couldn't do this
| because "send me a copy of sort()" would be met with "which
| sort()?". Whereas with unison every different sorting
| implementation would have different hash, so there would be
| no confusion.
| Nullabillity wrote:
| That makes sense as a build system (and is more or less how
| Nix works). The question would be why you'd subject your
| _source code_ to this.
| mst wrote:
| there was a paper that implemented an r7rs compatible
| module system for termite scheme that used hashes for
| identification for netework transfers of code but left
| the source files still normal - I think focusing on the
| textual representation too much misses the point a bit
| here.
| torginus wrote:
| I'm not totally convinced by this.
|
| - Storing the AST on the disk in a million files is not
| necessarily the best use of the filesystem. In contrast, most
| languages store text files on the disk, and build up a similar
| AST in memory only
|
| - You can't view your code without special tools, which means
| all text editors/version control etc. need to be Unison-aware
|
| - Since the language is append only, all edits look like
| additions in version control
|
| - Their solution for the diamond problem (depending on multiple
| versions of the same library) is having hard dependencies on
| exact versions, and including both copies can be at best
| wasteful, at worst bad (what if v2 fixes a bug that was in the
| v1 dependency), I think this is a hard problem, and the reason
| why semver exists
|
| - As others have mentioned, the append-only nature of the
| language makes bugfixes difficult
|
| - Solutions that dynamically discover code dependencies and
| automatically run tests exist for both procedural and
| functional languages
|
| - Detecting that 2 things are the same through hashing is
| nontrivial, can it detect that 1 + x + 1 is the same as x + 2?
| The ASTs are different
| asoltysik wrote:
| > Storing the AST on the disk in a million files is not
| necessarily the best use of the filesystem
|
| A new codebase format just uses a sqlite database instead of
| a million files
|
| > Since the language is append only, all edits look like
| additions in version control
|
| Traditional methods of showing change in verson control, that
| is text diffs, don't make sense here anyway
|
| > Detecting that 2 things are the same through hashing is
| nontrivial, can it detect that 1 + x + 1 is the same as x +
| 2? The ASTs are differen
|
| It can't detect that. It if could it would be pretty cool,
| but I don't think it would improve the usability too much
| the-smug-one wrote:
| What's the point of detecting that 1 + x + 1 is the same as
| x + 2 anyway? If I wrote it in one way, I meant it to be
| that way for a reason. Should it also be able to prove
| arbitrary code is semantically equivalent? Well, it can't
| do that for obvious reasons.
| lamontcg wrote:
| Loading both copies of a library can be very useful to deal
| with the situation where one piece of code has been ported to
| v2 (due to bugs/features or just generally keeping up with
| updates) and another piece of code is hard blocked on the
| v1->v2 migration because it is much more costly, and its
| possible that v2 is actually buggier for that other use case.
| There's a bit of a naive idea that software always gets
| better for everyone and that projects have an infinite amount
| of spare time to drop everything to bump dependencies. That
| feature is actually very useful.
|
| (Which is not to defend the rest of the append-only
| immutability of the rest of the language, that looks a bit
| whack -- but then I've seen whack stuff get wildly popular,
| so I have no idea -- but while having 2 versions loaded at
| the same time might be useful I'm not sure I want to deploy
| every version that has ever existed that smells way too
| bloated)
| torginus wrote:
| You are right - but choosing the correct solution imho
| needs to be done with human oversight - I think a semver
| based dependency resolution works great here, for example
| if bar requires foo 1.0 and baz needs 1.0.1 they will
| happily use the same version, but if baz used foo 1.1 they
| would use the separate ones.
| lamontcg wrote:
| Except 1.0.1 can fix a bug that one piece of code needs,
| while another piece of code can be happily bug dependent
| upon it.
|
| You can scream at the developers that they've violated
| semver but a "bugfix" is entirely subjective (relevant
| xkcd, spacebar heating, etc).
|
| And even when developers violate semver in a point
| release the problem still exists. They actually rarely,
| if ever, rollback with a 1.0.2 that is equivalent to
| 1.0.0 and instead usually move forwards.
|
| And if you have a language that supports loading 1.0 and
| 1.1 then there's no point in being artificially
| constrained over which two versions can be loaded at the
| same time based on the label, the underlying framework
| shouldn't be built to care. There's no need for a multi-
| version library loader to care about what a bugfix is.
| slver wrote:
| SemVer remains a pragmatic approach that works in vast
| amount of cases. It's unclear what alternative we have
| here which works in more cases.
| lamontcg wrote:
| We don't have any better alternative, but lets not be
| naive about it when it comes to building bits of
| framework.
|
| Semver would just be an artificial impediment at this
| level.
| slver wrote:
| SemVer is an impediment only if you insist to make it so.
| fastball wrote:
| I think another key idea is that you're still thinking
| about libraries as complete packages where you kinda
| install two versions of the same thing. But it seems more
| likely in the Unison ecosystem that you'd end up with the
| ability to much more easily only extract the specific
| functions you need.
|
| So say there is v1 and v2 of a utility lib in my dep
| tree, but actually only using func A from v1 and func B
| from v2. Then I just have the AST of v1.A and v2.B in my
| deps and everything works.
| Nullabillity wrote:
| You still need some unit of atomicity to be able to
| maintain invariants. You can't combine
| HashMap_LinearProbe::insert with HashMap_Chains::remove,
| because they both depend on implementation details in
| order to maintain HashMap's invariants.
| jackcviers3 wrote:
| Semver doesn't help in the case of transitive binary
| incompatibility. If lib A depends on B v2, and lib C depends
| on B v1, and application D depends on A and C, you cannot
| load a version of B that satisfies D, A, and C. Semver tells
| you that B 1 and B2 are incompatible, but not how to solve
| the issue.
|
| Unison solves the issue - there isn't any binary
| incompatibility, because the transitive versions of Bv1 and
| Bv2 cannot be in conflict - the function references are to
| guaranteed unique and different versions of the art.
|
| As for bug fixes - you can specify in your code exactly which
| version to use.
|
| As for editors needing to be unison aware - they just
| delegate everything to the compiler via lsp and bsp.
|
| Bug fixes are no more difficult than making the change. A new
| version is created, and your code can now depend on it. Old
| code will still run off of the old version. It's up to the
| code owner to decide to use the new, but fixed version.
|
| Version control is all handled in the language itself.
|
| As for the hard hashing problem... Runar is a particularly
| intelligent individual. I expect that his algorithm works
| pretty well.
|
| The first argument about storing the ast is moot in an age
| where cached compiled typescript, Python, and .class files
| take up inordinate amounts of disk space.
|
| > Solutions that dynamically discover code dependencies and
| automatically run tests exist for both procedural and
| functional languages
|
| Eh. Piping and yarn ain't got nothing on maven and ivy and
| apt. But yes, dependency management isn't anything new under
| the sun. Dynamically resolving individual function versions
| in packages alongside binary incompatible functions is.
| infogulch wrote:
| I think Unison paired with a strong graph database instead of
| the filesystem would be a powerful combo. It would very
| naturally represent the AST graph directly and would benefit
| from graph db optimizations. The cost would be the need to
| invest a lot in new tooling: you'd want a graph db-based
| source control implementation that offers similar
| cryptographic certainty to git; you'd have trouble using
| existing tooling directly like text editors that expect files
| on disk; etc.
| mpweiher wrote:
| > identified by a hash of its implementation
|
| Sound a lot like darklang.
|
| Like others, I am dubious about this being in any way a useful
| feature. Separating implementation from name (/interface) and
| binding to that interface/name instead of the implementation is
| one of the fundamental and _useful_ parts of abstraction.
| brundolf wrote:
| > 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
| iamevn wrote:
| it'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 wrote:
| > 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 wrote:
| Perhaps 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
| [1]http://deliberate-software.com/christmas-f-number-
| polymorphi...
| __david__ wrote:
| This 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)?
| 0_gravitas wrote:
| I'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 wrote:
| I 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-
| ru...
| prezjordan wrote:
| Strongly encourage anyone reading this to take 20 minutes to
| download ucm and run through the Getting Started guide:
| 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 wrote:
| The past threads appear to be (others?):
|
| _Unison: A Content-Addressable Programming Language_ -
| https://news.ycombinator.com/item?id=22156370 - Jan 2020 (12
| comments)
|
| _The Unison language_ -
| 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 - Aug 2019 (25
| comments)
|
| _Unison Language March Update_ -
| 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 -
| June 2015 (11 comments)
|
| _Unison: a next-generation programming platform_ -
| https://news.ycombinator.com/item?id=9512955 - May 2015 (128
| comments)
| janjones wrote:
| There is nice blog post summing up what's cool about Unison[1]
|
| [1] https://jaredforsyth.com/posts/whats-cool-about-unison/
| PaulDavisThe1st wrote:
| Good 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 wrote:
| There'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 wrote:
| I'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 wrote:
| Update: I'm skimming here
| (https://jaredforsyth.com/posts/whats-cool-about-unison/)
| and here (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
| jack_h wrote:
| Perhaps see my reply here
| (https://news.ycombinator.com/item?id=27654225).
|
| I think you may be misunderstanding what is being stored
| here. Now as a caveat I'm not familiar with this
| language, but I am familiar with the concept as
| described. They are not removing source code, rather
| source code is stored after some processing; in this case
| it appears to be after lexing, parsing, and type
| checking. I'm not sure exactly what is being stored, i.e.
| an AST, but it sounds like they're basically moving this
| stage of compilation/interpretation to be much earlier in
| the process.
|
| I'm assuming this database can be queried and the result
| can be rendered back to a textual presentation as well.
| Presumably this opens the door for syntax being divorced
| from language semantics since how the syntax is parsed
| into the database and how the database is rendered into
| text can be a client side decision rather than set in
| stone inside the compiler/interpreter. What is set in
| stone is the semantics of the database that everyone must
| agree to.
|
| Again, there's the caveat that I'm not familiar with how
| this language in particular is implementing this concept.
| jack_h wrote:
| I'm not sure I understand your question. Could you elaborate?
| jack_h wrote:
| Storing code in a database is super cool stuff and is something
| I've been thinking about for a number of years. I'm actually
| surprised this development hasn't happened sooner since
| basically all tooling is forced to deal with the limitations of
| storing source code as text.
|
| The article gives an example that most programmers would be
| familiar with; canonicalization so that version control and
| code reviews go smoothly. Version control also becomes somewhat
| simpler as it can compare the structure of code rather than the
| structure of a sequence of characters that still must be lexed,
| parsed, etc. There are lots of other areas where storing code
| in a structured database of some sort would benefit tooling as
| well. One example is the use of language servers to index,
| perform continuous recompilation, perform cross-reference
| lookups, and offer code completion. With a structured database
| a lot of this becomes relatively trivial.
|
| I'll definitely have to look into this language further as I'm
| curious about how their database is designed.
| grawprog wrote:
| Thank 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.
| jiaminglimjm wrote:
| Programming language i18n.
| michael-ax wrote:
| I'd love to see this in c, for scheme/racket.
| jjfeiler wrote:
| The 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.
| dthul wrote:
| An 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
|
| 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.
| imtringued wrote:
| No, they just need to use FUSE and provide file system level
| access to the source code.
| dthul wrote:
| Yes, I thought about something like that. Being able to map
| it to the filesystem and back to the Unison database.
|
| But then, what is the point of this content addressed code
| again? What do we gain from it that we don't already have
| now? With current file based version control you already have
| an append only repository, code is never deleted from the
| .git directory, it's just not always mapped to a file in the
| source code directory (until you check out an old revision,
| that is).
|
| Edit: I guess Unison still has the unique feature that
| dependencies are referred to by identity and not name.
| brundolf wrote:
| This is an interesting choice. Any language or framework has to
| make a dozen or more choices between doing something in a way
| that's compatible but compromising, or bespoke but... bespoke.
| It's always a painful choice in my experience. This one is
| particularly bold, though.
| adrusi wrote:
| It's afaict a necessary decision, since unison is designed
| around the possibility of having multiple versions of the
| same function referred to be the same name.
| adrusi wrote:
| FWIW because of how unison works, you get a lot of the benefits
| of version control without using any proper version control.
| Probably for small, single dev projects version control would
| just be redundant.
|
| That's not to say this isn't a limitation the project will need
| to overcome to be useful, just a caveat.
| zawodnaya wrote:
| In 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/ where you can look at
| the base library, and some (contributed?) libraries as well.
| dthul wrote:
| I 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 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).
| wyager wrote:
| This 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_ wrote:
| No, but it's planned; probably in the form of implicit
| parameters.
| auggierose wrote:
| Submission inspired by
| https://news.ycombinator.com/item?id=27651197 , I guess
| WillDaSilva wrote:
| They 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.
| teraflop wrote:
| Isn'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 wrote:
| What 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?
| JoshTriplett wrote:
| Seems 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.
| lpointal wrote:
| Unison is already the name of a bidirectional files
| synchronization software (AFAIR developped in OCaml).
|
| https://www.cis.upenn.edu/~bcpierce/unison/
| pvg wrote:
| Previously:
|
| https://news.ycombinator.com/item?id=22009912
|
| https://news.ycombinator.com/item?id=9512955
___________________________________________________________________
(page generated 2021-06-27 23:00 UTC)