I am working on a project at work that may involve some kind of language, and the language essentially came up because we need a way to define an arbitrarily large abstraction, effectively behaving as an intermediate layer between multiple different front-ends and a backend.
When I learned Haskell at University there was a lot of emphasis on EDSL (embedded domain specific languages), where haskell allows you to define grammars inside haskell. There are many examples of EDSL:s in other langauges but Haskell takes things a bit further. I think there could be a good point in allowing such approaches in more languages. I heard that Rust has ADT:s, which is a good building block for EDSL:s.
It might make things a lot clearer, or it might make things over engineered. I'm a bit on the fence about it. It probably makes things more manageable in the long run.
The point of Building an EDSL could be to isolate the business logic from everything else. This should be a big benefit since for most cases it should be possible to make everything else from off the shelf commodities.
This is perhaps clearest in lisp because there is no syntax to get in your way (kind of the opposite approach to operator overloading).
Perhaps the most interesting way you can approach this is by designing the language first and then figure out how to implement it.
Yeah, I'd say if you're not creating a "domain" in which solving the problem at hand is easier, you need to get back to the drawing board. That's true for language and API design.
To have a reasonable claim that you're writing a language, you'd need to write something with a different syntax and/or model of execution, and somehow embed it in your language. Arguably regexes and SQL count, though the perennial problem there is that to the host language, they're just opaque strings.
None of this is to say your APIs are bad. Embedding one language in another is hard--that's why they're so often just opaque strings. Beyond that, as this article points out, embedding a new language gives anyone working with your code a significant obstacle. For most things, little languages aren't the right tool--standard imperative/functional programming goes a really long way.
It can be. They're called EDSLs, "embedded domain specific languages". The point is to embed the language semantics in the host language via judicious choice of data types, and then methods implement semantics-preserving transformations on them. The more expressive the type system, the more expressive the languages you can safely embed in the host language, and you then have all the debugging capabilities and libraries of the host language at your disposal.
This pattern is very common in Haskell, Oleg is well known for doing this with OCaml [1], but you can also do this in typical OO languages like C#. Arguably C#'s IEnumerable<T> interface is such an EDSL for set programming, and here's a simply typed lambda calculus [2], here's an SKI combinator calculus [3], here's a stack-based language [4], and here's a logic programming EDSL based on µKanren [5].
[1] https://okmij.org/ftp/ML/#DSLs
[2] https://higherlogics.blogspot.com/2008/09/mostly-tagless-int...
[3] https://higherlogics.blogspot.com/2013/09/combinator-calculu...
[4] https://higherlogics.blogspot.com/2009/01/embedded-stack-lan...
[5] https://higherlogics.blogspot.com/2015/02/kanrennet-featherw...
And while you probably don’t embed it as a string, you do basically have a shim layer between the host language and the natural ways of expressing a logic program.
My point is something like “if you’re doing something like SQL or regex or minikanren, you have a claim to implementing your own language, but the normal case is just another API.”
There is a reason we’re talking about Oleg! He’s really unusual (in a good way).
Since object orientation brought the possibility of adding little languages to the masses and a few decades later value objects and lambdas and generics where added to all OO languages, a postmodern view may be quite an applicable and useful perspective to deal with this question.
This begs the question: what is the benefit of treating nearly all program writing as "language design".
Using that frame of reference I can use it to spot where my abstraction/program design breaks down when I start using too much "raw programming language" to glue between different parts of my program together. That suggests I have a gap in how my domain objects relate to each other.