Haskell - PureScript Transpiler

Hello, everyone! thx for the adding to the group!

Is there some “isomorphic” tool, way to transpiler PureScript <=> Haskell both sides ?

1 Like

I don’t think so. There’s a few issues between the two languages as well:

  • PS is strict; Haskell is lazy. Some things written in Haskell won’t be performant (or possibly stack overflow?) in PureScript.
  • Haskell has some language features that PS doesn’t have and vice versa.
  • The libraries both languages have are not necessarily compatible.

Offtopic, but related: I was thinking about implementing a transpiler from Elm to PureScript and transpile all existing packages. I think in this direction, it might work, since everything that can be expressed in Elm can be expressed in PS. I didn’t start the project though, because while it would be fun to develop, I don’t think the result is very helpful and there would be a lot of users interested in actually using it.


I think the idea is not that bad (I surely have some use cases) but I guess you’d have to have the elm-runtime in there too, plus the stuff for ports so this might be quite some work :wink:

1 Like

Yes, I see. It could not be possible then to identify the expressions where Haskell use thunks for implementing its lazy evaluation and translate them into the equivalent strict expressions in Purescript?. In this case, it could be feasiblein theory to do a homomorphic transformation and to yield a version of the haskell code that behaves in the same well as the original, by preserving the structure and behavior of the original code. (?).


Well that translation is not obvious to me. After all you can express more with non-strict evaluation strategies.
If you want it to behave the same you’d need the same lazy runtime simulated IMO and then it’s probably easier to wait/use GHCjs or the webassambly backend of GHC

1 Like

Thx for the reply

Let me show a little example to understand the matter better.

For instance lets say that we have such a haskell snippet:

add x y = if x <= 0
then x + y
else let x’ = x - 1
in add x’ (y + 1)

So far I understand if x is greater than 0, it performs the computation x’ = x -1 and creates a thunk for the expression add x’(y+1) , right? this thunk should be stored in memory and evaluated later on when the result is needed.
OK, then we can convert the expression in the haskell function to Purescript without thunks as it follows:

add x y = if x <= 0
then x + y
else let x’ = x - 1
y’ = y + 1
in add x’ y’

It is clear now that unlike the haskell code there are not thunks stored in the memory. Instead the intermediate values x’ and y’ are calculated inmediately. That means so far I understood that the code willl be evaluated strictly and will not delay any calculations yielding the same result.

Is it all this stuff right? could it be extended to deal with other expressions?

Well not exactly:

add x y = 
    if x <= 0
    then x + y
        let x’ = x - 1
        in add x’ (y + 1)

it depends how you use it - if you just do let x = add 4 5 and let’s assume x is not pruned (used somewhere) than x itself will point to a / be a thunk.
Now let’s say you evaluate that somewhere along the line (let’s say in GHCi by doing x - this will print the value so it does call show on it and prints it - this usually will fully evaluate … well usually).
Then something along the lines of what you describes happens: it needs to evaluate the first if for that it needs to evaluate the x there - so your 4 gets evaluated (well it’s a value anyway) and the if evaluates to the else - there x will be a thunk at first and it returns add ´x(y+1)` (y+1 will be a thunk also), and so on.

See that’s the point: it’s almost impossible to tell when a thunk will get evaluated as this is driven by need/runtime - my hunch is that a static check to this would be equivalent to the halting problem (so unsolvable)

Yes you can often translate into strict evaluation but the behaviour will change and some tricks like this:

or True _ = True
or False x = x

> or True undefined ... evals to True

will be nasty to handle (and those tricks are everywhere in Haskell and they are used!)

1 Like

Thank you for the thoroughness of your reply.

Thinking about the problem of evaluating or simulating in Purescript the behavior of the run-time thunks in Haskell, I wonder if it could be feasible to implement that in Purescript with monads/profunctors which effectively delay the execution of the computations according with the context of the monade/profunctor

Following with the former example. To circumvent the problem of the undefined/error avoiding by the lazy but not the strict evaluation one can maybe try something like this with the Eff monad:

Blockquote :
orTrue :: Boolean → Boolean → Boolean
orTrue = \a1 a2 → if a1 == true then true else a2
or :: Boolean → Boolean → Eff (console :: CONSOLE) Boolean
or = \a1 a2 → if a1 == true then return true else return a2

or True _ would evaluate to True. The _ in this context
would be equivalent to undefined, but since the first argument is True, the function returns True regardless of the value of the second argument .

Now applying the same solution in the case of the infinite loop/recursion:

Blockquote :
– Import the Eff monad, which provides a way to execute computations with side effects
import Control.Monad.Eff
– Define a type alias for the Context monad:
type Context a = forall r. (Int → Eff r a) → Eff r a
– Define the add function, which takes two arguments x and y and returns a Context Int value
add :: Int → Int → Context Int
add x y =
– Use the if statement to check the value of x
if x <= 0
– If x is less than or equal to 0, return x + y as the result
then \k → k (x + y)
– If x is greater than 0, continue the computation
else \k →
– Bind the result of add (x - 1) (y + 1) to a new value x'
let x’ = add (x - 1) (y + 1)
– Pass x' to the continuation k
in x’ k
– Define the runContext function, which takes a Context a value and returns an Eff r a value
runContext :: Context a → Eff r a
runContext c = c id

IMHO it seems to be feasible with the help of the Eff monad to solve the problem of converting the Haskell expression into the “strict” Purescript.

It might be quite interesting to create a (simple, limited in scope) implementation of a PureScript → Haskell compiler just to see how performance would be compared to running PureScript on NodeJS, or the pscpp (compiling to C++) or psgo (compiling to go) backends. The amount of translation that needs to happen is probably much less when going to another functional language (especially when forcing Haskell into Strict mode in the compiled modules) vs. an imperative/class-oriented language like C++.