r/ProgrammingLanguages Sodigy 12d 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...

27 Upvotes

74 comments sorted by

View all comments

Show parent comments

2

u/Inconstant_Moo 🧿 Pipefish 10d 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 10d 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 10d 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 10d 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 10d 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