OK, so as @wdanilo written above, it’s possible, not very streamlined though.
Using luna from the console will require rebuilding the
luna/shell project from https://github.com/luna/luna, as described in the README.
Using the new library from Luna Studio will require rebuilding Luna Studio and using the dev version. The whole process is described in the https://github.com/luna/luna-studio. You’ll need to change the location of
luna package in
build-config/backend/stack.yaml. You can make it point to your local copy of
luna repository or another (forked) repo – otherwise it will build against the master version of
One thing to keep in mind – this is very temporary and very hacky. Anything you create this way will not be share-able with others (unless they too run your dev version of Luna / Luna Studio). This mechanism is intended for functions that are completely necessary for the language to function well (low level stuff). For extension libraries, we’re preparing an early version of Haskell FFI, that will allow to actually share the libraries and not recompile the whole compiler every time you change something. The first version will be available rather soon and will probably utilize many of the mechanisms described here, so the haskell code you create probably won’t go to waste after that – you should be able to use most parts with the dynamic FFI.
However, if you feel that something is really missing from the standard library (like, well, reading input from stdin), this is the way to add these functions and in such cases we’ll happily accept pull requests.
OK, now on to the real work.
The new function needs to be added here: https://github.com/luna/luna/blob/469d86eb6f938485cf38e22c36cd3f8e06b1fc9f/stdlib/src/Luna/Builtin/Std.hs#L1001
This way it will become visible for the compiler and can be used throughout Luna code.
The key in this map is the name as seen from Luna. The value is the runtime representation of your function. How do you get a runtime representation? Let’s break one of them down:
let readFileVal :: Text -> LunaEff Text
readFileVal = withExceptions . fmap convert . readFile . convert
readFileF <- typeRepForIO (toLunaValue std readFileVal) [textT] textT
The first part is the definition of
readFileVal. This is an ordinary Haskell function. The
LunaEff monad is a HS-level monad in which all Luna computations are executed. It handles IO and throwing exceptions. Not much more to say about this – just write your code in haskell, if it runs in
withExceptions (the latter rethrows IOExceptions into the proper Luna exceptions), if it’s pure, leave it be.
readFileF is the full representation of a function and this is what you want to export. There’s two parts to this.
toLunaValue std call – this one takes a Haskell value and converts it into a Luna function. The existing instances will allow you to convert most common Luna types, such as
List and many more. It can also handle functions, assuming the arguments and return values are supported. Also automatically handles pure vs. monadic computations.
Then there’s the
typeRepForIO function – this one takes a luna value (covered above) a list of types for arguments (Luna types, this is how you tell Luna “this primitive function has the type such-and-such”) and then a type for the return value. There is also a pure counterpart of this, named
typeRepForPure. Luna typesystem tracks monads under the hood, so use these depending on whether your function does IO or not. I’d recommend looking around the current implementation of primitive functions to get a better understanding how this whole system works.
In case of any problems, don’t hesitate to ask for help!