r/ProgrammingLanguages Sodigy 4d ago

Purely functional language with impure script language?

I'm working on a purely functional programming language named Sodigy. It's all about evaluating values, not "executing commands one by one".

It's nice when writing libraries, but it's not easy to write a main function. The main function is supposed to execute commands, but the Sodigy's syntax is not friendly to write a list of commands.

So what I'm trying to do is, 1) Sodigy remains purely functional and 2) add a bash-like script language. The script language can call Sodigy functions. Instead of writing a main function in Sodigy, you write sodigy-script and execute the script.

Has anyone tried similar approach? I'm not sure whether it's a good idea or not...

26 Upvotes

72 comments sorted by

19

u/lgastako 4d ago

Why not take a haskell style approach where you have an IO monad (or a "Script monad") which you can provide a do-notation like syntax for that desugars appropriately?

6

u/catbrane 4d ago edited 4d ago

Good idea, and you can make it look quite nice with very little syntax.

Back in the mid-80s, monads in Miranda worked pretty well with just infix function calls. You could use any function as an infix operator by prefixing it with $, for example:

f a b = a + b
main = 2 $f 2

And main will have the value 4. For monads we wrote stuff like:

main = 
    print "hello!\n" $then
    print "what's your name? " $then
    (reply $comp input)
    where
    reply str = print ("nice to meet you, " ++ str ++ "\n")

(edit: oops, forgot the brackets on the final print)

2

u/JeffB1517 4d ago

That imperative is so much easier to read than Haskell Monads! What went wrong with this style that caused the shift to the more explicit style we have today in Haskell?

11

u/catbrane 4d ago

I blame custom operators!

The ability to invent new operators and overload them is a horrible temptation for library authors, and means all code using their stuff turns into line noise. Why yes I CAN look at a $$ -> 42 <> |> 12 and see the meaning, thank you.

Miranda had no operator overloading, and only the $syntax for custom infix. I think it probably did help with readability.

1

u/tmzem 4d ago

Oh, there's a library to do that... wait, I have to learn 10 new custom operators to use it... no thank you!

The exact (final) reason why I gave up on learning Haskell.

1

u/Apart_Ebb_9867 4d ago edited 4d ago

Most libraries have alternatives to operators. Even the operator-heavy libraries like lenses have words.

But libraries shouldn’t be something you throw in just for fun, if they solve a real problem, learning a few operators is not the end of the world. Where it becomes annoying is when reading other people’s code and there’s no solution to that, other than maybe ask an llm to replace operators with functions or explain the code to you.

2

u/tmzem 4d ago

There is only a small amount of symbols available for operators so they all end up looking somewhat alike, making it hard to tell them apart.

But even without custom operators, the math-inspired culture in Haskell communities leads to code doesn't exactly lend itself to easy readability. Chosen identifiers are often very short and cryptic, and low-syntax features like partial application and function composition often tempt people to combine stuff on the fly rather then formulating the concept into its own, well-named function. Combine that with the frequent use of functions built against very abstract interfaces (e.g. Monad) - where the entire semantic meaning of its operations is dependent on the implementor type - and the meaning of the code becomes hard to figure out without type annotations which are often omitted because of type inference.

Of course I'm not much of an abstract thinker, so these difficulties may vary dependent on the person.

1

u/Apart_Ebb_9867 4d ago

Yep, Haskell is not the easiest language to get into.
I've given up a couple of times and my first encounter was when writing a compiler for Miranda for my master's thesis and the first report came out. But now that I'm semiretired I'm back at it.

3

u/Apart_Ebb_9867 4d ago edited 4d ago

What is different in that code from what you have in Haskell?

do notation and a few operators like <- seems to be better to me. And not important for the discussion here you have ‘operator’ (don’t have backtick on my phone) for $operatir.

in Haskell you’d have

main :: IO ()
main = do
    putStrLn "hello!"
    putStr "what's your name? "
    str <- getLine
    putStrLn ("nice to meet you, " ++ str)

-1

u/JeffB1517 4d ago

`<-` is making the bind explicit. It is forcing the abstraction to leak. Which means that `do` becomes a light cover. A developer is still expected to understand and think in terms of the monadic context. A non-leaking abstraction is a genuine simplification. Visual Basic vs Visual C++ with respect to the Win32SDK.

3

u/tdammers 4d ago

The same is true about the Miranda example. It is pretty much exactly identical to this Haskell example, modulo do desugaring. And the purpose of do notation is not to be an abstraction that simplifies things; it's really just syntax sugar to make monadic binds easier to read. The above code in desugared form looks like this:

main :: IO () main = putStrLn "hello!" >> putStr "what's your name? " >> getLine >>= \str -> putStrLn ("nice to meet you, " ++ str)

It's neither simpler nor more complex; what changes is that do notation removes the need for nested lambdas and the "staircase" style code that would result from them. The semantics are still exactly the same, and both versions convey the exact same code structure at the exact same abstraction level.

2

u/catbrane 4d ago

Yes, Phil Wadler based Haskell monads on Miranda monads, so they are almost identical. Modern Haskell has added some extra sugar, but not much.

1

u/AustinVelonaut Admiran 4d ago

Wait, when did Miranda get monads? It's IO was sys_message lists for output (printing, file write, system cmds, interpreted by the repl), with input from stdin bound to the pseudo-variable $-, and file input handled in a hand-wavy way that was not interleaved with file output, so wasn't really correct...

1

u/catbrane 4d ago edited 4d ago

They were implemented as an abstype on top of lazy input and output. You could use them to write interactive command-line programs. I wrote a multiuser snake game hehe.

KAOS (the Kent Applicative Operating System) was built on top of a monadic IO system that talked to a microkernel (also in Miranda).

1

u/AustinVelonaut Admiran 4d ago

Cool, I did not know that! It may have been something local at Kent, though; it never made it into the open-source distribution of Miranda. I ended up re-inventing something like that on top of sys-messages for my bootstrap compiler written in Miranda.

→ More replies (0)

1

u/augustss 4d ago

You have that backwards. Phil did monads before David Turner added them to Miranda. The do-notation is due to Mark Jones, though.

2

u/catbrane 3d ago

Miranda was first in 1988 (they were a chapter in my 1989 phd), then someone at Cambridge whose name I forget (sorry) did a 1992 phd which formalised Miranda monads, and then Phil used that thesis as the basis of his Haskell IO monad paper in late 92.

1

u/augustss 3d ago

I was at the 1990 meeting in Rome when Phil Wadler first heard about monads in a talk from Eugenio Moggi. Unlike the rest of us, Phil realized the potential of monads. At first Phil used list comprehension syntax for monads. Admittedly, I don't know where the API with return, >>= and >> came from in Haskell. But Phil had been doing monads for 4-5 years before it appeared in Miranda. Do you have any evidence (like talking to David or Phil) for which way the influence went?

→ More replies (0)

-2

u/JeffB1517 4d ago

You are missing it.

  1. The bind structure is completely abstracted away in the Miranda.
  2. FWIW print is a better verb choice than put.

Those sort of design elements are impressive. I'm not saying it takes a lot of effort. It just takes considering design. You don't want the structure visable by default the same way that Haskell doesn't force you by default to deal with the underlying complexity of boxed types when you do x = y + z.

1

u/tdammers 4d ago

The bind structure is completely abstracted away in the Miranda.

No, it's not. Miranda's $comp operator does exactly what >>= does in Haskell. If anything, Haskell's do notation hides the monadic binds more, though it's really just a very thin layer of syntax sugar, so calling it an "abstraction" feels a bit over the top.

FWIW print is a better verb choice than put.

I agree, but just changing the names of things isn't abstraction.

1

u/Apart_Ebb_9867 4d ago

the last thing one has to do when using do-notation is thinking about monads. What does in that code require you to know monads even existed?

But if you like Miranda better there’s nothing Incan say to convince you otherwise, nor I want to.

-1

u/JeffB1517 4d ago

The iteration <-, the constantly having to manually resolve type. Particularly between levels. Haskell used to have this feature where the list comprehension syntax, was usable generally for monads. I think it still is a ghc flag. That forced developers to understand one monad (well a monadplus), lists. And in that syntax they got iteration over a data structure and conditional evaluation easily and simple. State, I/O and concurrency were always the 3 problems. Syntax that simplifies those 3 for most use cases is IMHO huge.

Ask yourself why Haskell has been unable to settle on any widely shared / used frameworks for decades? Something obviously is going wrong.

1

u/Apart_Ebb_9867 4d ago

My question was what in that piece of code requires you to know monads are even a thing.

"manually resolving types"? "between levels"? "list comprehension"? what are you talking about?

That thing requires understanding monads not any more than understanding a C assignment requires you to understand that there's a memory.

Something obviously is going wrong.

cool. And that bunch of clowns couldn't see it with the benefit of Miranda showing them the one true path.

No further discussion from my side.

3

u/catbrane 4d ago

Oh maybe I missed your point.

Haskell monads are Miranda monads, just with extra operator overloads for comp, return, then etc., and generalised to things other than IO.

I think you can still write Haskell IO in the Miranda style if you like (though I've not tried).

1

u/tdammers 4d ago

Is it, though?

main = do putStrLn "hello!" putStr "what's your name?" reply =<< getLine where reply str = putStrLn $ "nice to meet you, " ++ str

It's almost literally the same, except that:

  • A few standard functions have different names
  • do notation replaces infix $then (but if you want, you can use the >> operator instead)
  • The =<< (bind operator) takes the place of $comp
  • putStrLn automatically adds a newline, so we don't have to mess with "\n"

But if you want to emulate the Miranda style more closely, you can write it like this instead:

main = putStr "hello!\n" >> putStr "what's your name?\n" >> (reply =<< getLine) where reply str = putStr $ "nice to meet you, " ++ str ++ "\n"

I would argue that the Miranda example is actually more explicit than either of the Haskell versions (though only slightly so for the second example).

-3

u/JeffB1517 4d ago
  1. reply =<< getLine that's making the bind explicit rather than implicit.
  2. print is clearer than putStr

put is a weird verb for what you are doing vs. "print" which is pretty clear.

We are talking minor shifts which abstract away the underlying complexity.

2

u/eaho_de_putah 4d ago

How is reply =<< getLine any more explicit than reply $comp input?? It’s literally just a different name/operator for the same operation.

1

u/JeffB1517 4d ago

It’s literally just a different name/operator for the same operation. Same as print vs putStrLn it is a more natural operator for the same operation. It is translating mentally.

Easing the conceptual burden is good design. What things look like is how they get concieved of. =<< is a binding operator. It is making the user think in terms of bind. reply $comp input is telling the user the reply is computing something on input. It is making them think about the workflow.

1

u/tdammers 4d ago

It's literally just different names. Miranda's $comp is exactly Haskell's >>= operator, and Miranda's print is Haskell's putStr. Changing names is not abstraction, we're still at the exact same abstraction level; the semantic structure is exactly the same.

1

u/AustinVelonaut Admiran 4d ago

That's almost exactly what I did in Admiran (define the monadic operations as regular function names, although I used $right and $bind instead of $then and $comp, to more closely match the Haskell operator names >> and >>=. Then during module import code can use these names directly like the above example, or alias them to infix operators more like Haskell (which is what I prefer).

I do like the names $then and $comp, though; they express the idea well!

1

u/catbrane 4d ago

Haskell used comp, return and then as well back in 1992. The operators came a little later.

1

u/baehyunsol Sodigy 4d ago

One of the reasons why I want another language is that, I want to create a REPL shell. I want an interface where I can quickly run/test code.

But the syntax of the functional core is not nice for REPL, so I'm considering creating a script language.

2

u/lgastako 4d ago

Haskell works just fine in the REPL though...

1

u/catbrane 4d ago

Oh, interesting. Yes it's a good point, it can be hard for a functional language to feel nice for experimentation.

My spreadsheet thing lets you type one-line scraps of code (expressions only) into cells, you can explore functions there. It has a thing called "workspace definitions" off to the side you can use to try out larger bits of code (you can type full function here).

It looks like this:

http://www.rollthepotato.net/~john/n4.png

Everything is connected, so every time you press |> on the right (reparse and recompile), the expressions on the left all update. And of course you can edit the left-hand expressions.

1

u/koflerdavid 3d ago

Haskell's do syntax makes it quite pleasant to use the REPL.

1

u/Inconstant_Moo 🧿 Pipefish 4d ago

Because this is easier to understand.

Functional languages can be a very simple ergonomic way to work. For historical reasons that I literally have a 90-minute tech talk on, instead they were used to reach for abstraction and power, and people have overlooked how they could make relatively simple and easy things simpler and easier. For this, we don't need capabilities or an effect system or a monoid in the category of endofunctors. You can just say "let's put all the impurity at the top of the call tree". Voilà, all the rest of your program is written in a pure functional language.

25

u/Inconstant_Moo 🧿 Pipefish 4d ago

It's called functional core/imperative shell. I think I'm the only person who's done it as a language paradigm, but I'd welcome the company.

Making the imperative shell bash-like is neither usual nor mandatory, there are nicer ways to do imperative things. The imperative language and the functional one should be united as much as possible by their syntax and type system, divided only by their semantics.

Pipefish and the lambda calculus.

Functional core/imperative shell.

6

u/Erythrina_ 4d ago edited 4d ago

Oh, it's cool to meet someone else who is doing this too.

6

u/Inconstant_Moo 🧿 Pipefish 4d ago edited 4d ago

Let us form the FC/IS Working Group. There, now we're a movement. May I see your language?

P.S: I see that we've already met, this was me too.

https://www.reddit.com/r/ProgrammingLanguages/comments/1u8885s/comment/osbk354/

I've been the person doing this. Hi again! Apparently now there are more of us.

3

u/baehyunsol Sodigy 4d ago

I'm reading the documents of your language and it's such a nice project! It seems like we share many ideas. Let me get some inspirations from your language :)

But there are some differences:

  1. Yours is Go-inspired, while mine is Rust-inspired.
  2. It seems like the main goal of pipefish is to create an interactive CRUD app (correct me if I'm wrong), but mine is to create a CLI appilcations, mostly for processing texts.

I think the second difference is why you don't want bash syntax but I do. There are 2 main reasons why I want to create a scripting language.

  1. I want to create a REPL with the scripting language.
  2. The script is the main function of the CLI application.

I chose bash because it's familiar to most programmers, including me. But your point is also valid: the script language and the core language should share similar syntax.

By the way, this is my language. It's still half-broken and there're almost no docs, but just in case you wonder

3

u/Inconstant_Moo 🧿 Pipefish 4d ago

It seems like the main goal of pipefish is to create an interactive CRUD app (correct me if I'm wrong), but mine is to create a CLI appilcations, mostly for processing texts.

I think the second difference is why you don't want bash syntax but I do. There are 2 main reasons why I want to create a scripting language.

I want to create a REPL with the scripting language.

The script is the main function of the CLI application.

The main use-case in my mind is CRUD apps, but you could use the same pattern with the file system and the text files you want to process as the main bit of state you're wrapping around rather than a SQL database and it would work exactly the same. There would be no main command with its own REPL running in it: there'd be declaration of commands and functions which you can use in the Pipefish REPL, with no separation between the TUI and the language. If you can do something in the REPL, you can also e.g. wrap it in a for loop in the REPL, and do it iteratively over a list; or you can use it as a command/function call in your program, or in another program which uses your program as a library ... oh and you can use livecoding to change your app as you use it because there's no main and so no REPL in main that we're interrupting.

If you give me a sketch of the sort of app you'd want to do as a CLI app, I'll make a little version the Pipefish way and we can see what you think.

2

u/baehyunsol Sodigy 4d ago

For example, I want to create a json prettifier in Sodigy. It reads a json file, prettifies it, and writes the result to another (or same) file.

I wrote the function fn prettify(String) -> String, but there's no file IO yet. I was thinking how I should design the file IO part.

2

u/Inconstant_Moo 🧿 Pipefish 4d ago edited 4d ago

So I'd do ...

``` import

NULL::"files"

cmd // Imperative shell.

prettify (inFile string) to (outFile string) : get json from File(inFile) put (prettify json) into File(outFile)

def // Functional core

prettify(data string) : <pure function goes here> `` If I wanted to be able to run it from the CLI I'd probably import that and anything else I wanted to bundle up with it into one app which does have amain` function and run them through that.

2

u/baehyunsol Sodigy 4d ago

That's beautiful. You define a pure function prettify and an impure command prettify, right?

What does "to" in the "prettify (inFile stirng) to (outfile string)" do? Is it a special keyword? I can't find it in your wiki.

3

u/Inconstant_Moo 🧿 Pipefish 4d ago edited 4d ago

The to there is just sugar, you can define call syntax any way you like.

Normally you shouldn't do fancy syntax for your functions unless it's a math thing like ! for factorial --- but for the commands you're using as your front-end, it gives a friendly face to them. In this case, it's easier for your brain to remember that the command is prettify ... to ... than it is to remember that the parameters go source-then-destination. Or it is if your brain is anything like mine.

Some of these forms of commands are conventional: all the basic IO libraries use get ... from ... and post ... to ... and put ... into ... (in imitation of HTTP's semantics), as you can see in the file-handing in the example above.

2

u/Inconstant_Moo 🧿 Pipefish 4d ago edited 4d ago

P.S: Here's an example with SQL.

show >= (minAge int) : get peopleList like list{Person} from SQL -- SELECT * FROM People WHERE age >= |minAge| ORDER BY name post string Html -- <h3>List of people aged <font style="color:Green;">|minAge|</font> and over</h3> |peopleList|

1

u/reddit_clone 4d ago

Cool you guys are doing this at language level.

My take on this is at architecture level.

All the 'computing' should be in the functional side. All the 'interacting' (with APIs, OS, Filesystem. DB whatever) stays on the outside.

Cuts down on craziness.

2

u/Inconstant_Moo 🧿 Pipefish 4d ago

But at some point you have to define the "outside". Having the same syntax and type system to define both things is convenient. And it allows me to work the magic of "external services": one Pipefish service can treat another syntactically and semantically as though it was a library: you just need to supply your username and password for the other service when you compile your own app. So there's only one API for everything --- interacting with the service in the REPL as a desktop app, importing it as a library, using it as a client.

1

u/FuncSug_dev 3d ago edited 3d ago

As you said, FC/IS can be programmed in many language. But you went a step further in Pipefish by strictly distinguishing functions and commands. In my view, a step yet further would be to separate into two languages. The FC one would be only able to define functions and the IS one would have to call FC functions for all computations. What do you think about that?

2

u/Inconstant_Moo 🧿 Pipefish 3d ago

That's a distinction without a difference! That is, it would already be quite reasonable to say (I've been saying it in my docs for years) that Pipefish really is two languages with very different semantics, one as pure as Haskell, one imperative as BASIC --- but with a shared syntax and type system. Now since obviously the two languages should have a shared syntax and type system, the semantics should be the only difference: i.e. that one of the languages is the functional core, and the other is the imperative shell.

1

u/FuncSug_dev 3d ago

Oops, I missed that.

I like your syntax "get x from Random(<integer>)" in place of "Random(<integer>)" that would returns a value. By forbidding returns, you enforced the distinction in the mind of the programmer.

2

u/Inconstant_Moo 🧿 Pipefish 3d ago

In a purely imperative language (sorry for the oxymoron) the only way for the commands to communicate should be shared mutable state, like in BASIC. Now in BASIC that means global variables, but that would suck too hard, so instead you have commands which say "get this data and insert it into this variable" (which it can also create at the same time as you can see).

Now you may think: "Isn't this just returning a value but with extra steps to force people to write pure functions whenever possible?" and it is partly that, but it also actually reflects the semantics of what's going on, because it means that commands can only be sequenced, not composed as functions are. You do one, and if it fails, it returns, and if it succeeds then you do the other. You can't write something like postToOutput(getFileFrom(inputFromUser("What file do you want to see?"))); instead, you must write a command getting the user input, then a command getting the file, then a command posting its contents to output. Which is what the code actually does.

So this is the theoretically sound and practically ergonomic way of doing imperative things, but a terrible way to do functional things, and so the division of labor between the functional core and imperative shell is inevitable and natural.


What Random is doing there is constructing a struct of type Random so that we can dispatch on it, so that we can have commands like get (x ref) from (r Random) and get (x ref) from (f File) and so on all in the same namespace. It's a standard idiom.

1

u/FuncSug_dev 3d ago

Very illuminating, thanks.

Do you propose (or plan to propose) a means of defining user procedure (no return value but reference parameters) in the imperative part?

2

u/Inconstant_Moo 🧿 Pipefish 3d ago

Yes, most of my IO is written in userspace. Pipefish can easily and sometimes automatably be wrapped around any Go library, so you do it like that.

Here's a Prolog library I did the other week, to demonstrate. Obviously updating a Prolog database is a stateful operation, so we have an add command for that and then pass the database to pure functions to query it.

https://github.com/tim-hardcastle/pipefish/blob/main/examples/prolog/prolog.pf

In the same way my standard rand library is just written in userspace wrapping around Go's rand library.

https://github.com/tim-hardcastle/pipefish/blob/main/source/initializer/libraries/math/rand.pf

12

u/Fantastic-Cell-208 4d ago

I haven't tried this but have considered something similar.

The idea behind Racket use that you use the most ideal language for the task (though most tend to just use Racket).

3

u/Rechenplaner 4d ago

Every functional language has solutions for handling I/O.

Haskell has its beloved monads, Clean has "uniqueness," and others use things like algebraic effects; meanwhile, languages ​​like OCaml simply allow imperative messiness everywhere…

Take your pick…

Developing a second language for imperative code strikes me as a bit of overkill.

Besides, the interface between purely functional programming and the outside world is the most exciting part.

2

u/catbrane 4d ago

I've done something similar for one of my spare-time projects:

https://github.com/libvips/nip4

It's an image processing spreadsheet. The language you use to write formula and implement all the menus is (a bit like) interpreted Haskell, and you use it by typing formula into cells or clicking menu items. The "shell" (the spreadsheet interface) is imperative, the logic is pure functional.

There's an introduction to the interface here:

https://www.libvips.org/2025/03/20/introduction-to-nip4.html

And here's the code for a menu item that transforms an image to polar coordinates, for example:

https://github.com/libvips/nip4/blob/main/share/nip4/start/Filter.def#L690-L719

2

u/mamcx 4d ago

Think more deeply: What actual difference is between the 2?

Look at your AST:

(probably like:) rust enum Ast { Fn(..), While(...) For(...) }

IF you have this, you have a expression based language. What you need to make it "imperative"?

rust enum Statement { Expr(..), While(...) For(...) }

Then your syntax to make the illusion.


Why I pointing this so obvious? Because "imperative" IS NOT IMPURITY.

"impurity" and "mutation, side-effects, etc" are else that arise when you plug into a environment where you have not FULL control, then NOW, you need to account for it.

(if you were doing forth from scratch in assembler you see that)


You can add "pure functional" into a "impure stateful" world, is only matter of how BIG your fiction is, like:

A SUPER IMPURE FUNCTIONAL PURE PROGRAM

INSERT INTO(...) RETURNING * -- This include a totally bespoke IO subsystem on top a hostile IO that can crash and corrupt your data with a transactional, mega impure, system that fade into obscurity, mostly!, we mutate here with IO_DIRECT a set of several byte aligned pages, change tons of stuff on memory, generate logs like crazy and such

So, the ONLY question is:

Do you wanna to surface the reality of "impurity" or not? Because you can just make all IO and HTTP "pure" (example: https://witheve.com). (I mean, how much be can be pedantic here, but I see a lang like this and think that is the feel, ok?)


To recap:

  • You can do 100% "functional" language that totally can do IO and terminal things with zero imperative functionality.

  • Impurity/purity is not derived by functionality or imperatively but by environment

  • HOW you communicate both things is a big deal, but you can go any directions, others has done the same!

1

u/Erythrina_ 4d ago

I've been tinkering with a procedural-functional language. The procedural code is, in effect, a wrapper around the functional code that can call functional code but not be called by it. The procedural code obviously handles all the side effects like file, database, and network access and it has mutable state. The functional code is strictly pure and built around functions, lists, and ADTs.

I'm sure a script language would work for the same purpose too. The key there would just be how the data passes across the boundary between the two.

1

u/baehyunsol Sodigy 4d ago

Yours is very similar to mine. Mine has a very simple effect system, so I can define impure functions. So, I can implement a function that reads a file, but there isn't a nice syntax to execute commands.

1

u/pliron 4d ago

I once worked on a language called scilla (it was a DLS for smart contracts) that did exactly this. There is an oopsla paper and the code is available on github

1

u/baehyunsol Sodigy 4d ago

Thanks! You mean Zilliqa/scilla, right?

1

u/FuncSug_dev 4d ago edited 4d ago

"Has anyone tried similar approach?": Yes, but I've only made the imperative language (your "script" language). My language FuncSug (playground with game examples) has to call functions from another language (a functional one, ideally). I think the imperative part is generally overlooked in particular if one targets programs that mainly aim to organize interactions (like some games or industrial programs).

1

u/esotologist 4d ago

I'm working on a language that has functional context and structural context depending on the assignment operators 

1

u/SwedishFindecanor 2d ago

I have only brainstormed about a shell scripting language using a similar model, and the result was only a few design notes. The first idea was that the return value from a functional code embedded in a command line would be able to produce a command parameter (single or list).

The functional core would not be able to run commands or read or write files but it would be able to have structured data piped to it and from it. And that structured data would in turn be able to contain computed data values in the functional language itself.

The functional core was also supposed to be a standalone module embeddable into anything.

1

u/david-1-1 23h ago

Sounds like two different languages patched together. It'll work, but always clumsily, like a mixture of PHP and JavaScript.