Generics in PureScript

module Main where

import Prelude
import Effect (Effect)
import Effect.Console (log)
import Data.Array (findIndex)
import Data.Maybe (Maybe(..))

-- As an example of a generic function, `slicesIndex` takes
-- an array of any type that can be compared for equality
-- and an element of that type and returns the index of the
-- first occurrence of v in s, or Nothing if not present.
slicesIndex :: forall a. Eq a => Array a -> a -> Maybe Int
slicesIndex s v = findIndex (_ == v) s

-- As an example of a generic type, `List` is a
-- singly-linked list with values of any type.
data List a = Nil | Cons a (List a)

-- We can define functions on generic types just like we
-- do on regular types.
push :: forall a. a -> List a -> List a
push v Nil = Cons v Nil
push v (Cons x xs) = Cons x (push v xs)

-- allElements returns all the List elements as an array.
allElements :: forall a. List a -> Array a
allElements Nil = []
allElements (Cons x xs) = [x] <> allElements xs

main :: Effect Unit
main = do
  let s = ["foo", "bar", "zoo"]

  -- When invoking generic functions, we can often rely
  -- on type inference. Note that we don't have to
  -- specify the types when calling `slicesIndex` - the
  -- compiler infers them automatically.
  log $ "index of zoo: " <> show (slicesIndex s "zoo")

  -- We could also specify the types explicitly if needed.
  let _ = (slicesIndex :: Array String -> String -> Maybe Int) s "zoo"

  let lst = push 23 $ push 13 $ push 10 Nil
  log $ "list: " <> show (allElements lst)

In PureScript, we use a different approach to generics compared to Go. Here are some key differences:

  1. PureScript uses parametric polymorphism, which is similar to generics in other languages.

  2. Instead of using a comparable constraint, we use the Eq typeclass to ensure that values can be compared for equality.

  3. PureScript doesn’t have mutable structures, so our List implementation is immutable.

  4. We use Maybe Int instead of returning -1 for not found cases, which is a more idiomatic approach in functional programming.

  5. PureScript uses forall to explicitly declare type variables in type signatures.

To run this program, you would typically compile it with the PureScript compiler and then run it with Node.js:

$ pulp build
$ node output/Main/index.js
index of zoo: (Just 2)
list: [10,13,23]

Note that the exact output format might differ slightly from the Go version due to PureScript’s data representations.