Generics in Idris

module Main

import Data.List

-- As an example of a generic function, slicesIndex takes
-- a list of any comparable type and an element of that
-- type and returns the index of the first occurrence of
-- v in s, or -1 if not present.
slicesIndex : Eq a => List a -> a -> Int
slicesIndex s v = case elemIndex v s of
                    Nothing -> -1
                    Just i  -> i

-- As an example of a generic type, List is already
-- a built-in generic type in Idris. We'll define a
-- custom LinkedList type to demonstrate.
data LinkedList : Type -> Type where
  Nil  : LinkedList a
  (::) : a -> LinkedList a -> LinkedList a

-- We can define functions on generic types just like we
-- do on regular types.
push : a -> LinkedList a -> LinkedList a
push x xs = x :: xs

-- allElements returns all the LinkedList elements as a list.
allElements : LinkedList a -> List a
allElements Nil = []
allElements (x :: xs) = x :: allElements xs

main : IO ()
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 type when calling slicesIndex - the
  -- compiler infers it automatically.
  putStrLn $ "index of zoo: " ++ show (slicesIndex s "zoo")

  -- We could also specify the type explicitly if needed.
  let _ = slicesIndex {a = String} s "zoo"

  let lst = push 10 $ push 13 $ push 23 Nil
  putStrLn $ "list: " ++ show (allElements lst)

-- To run this program, save it as Generics.idr and use:
-- $ idris Generics.idr -o generics
-- $ ./generics
--
-- Output:
-- index of zoo: 2
-- list: [23, 13, 10]

This Idris code demonstrates concepts similar to the Go generics example. Here are some key points:

  1. Idris has built-in support for generics, so we don’t need to explicitly declare type parameters in most cases.

  2. The slicesIndex function is implemented using the elemIndex function from Data.List, which returns a Maybe Int. We convert this to the same -1 behavior as the Go example.

  3. Idris already has a built-in generic List type, so we defined a custom LinkedList type to demonstrate generic type definition.

  4. The push function is defined for our LinkedList type, similar to the Go example.

  5. The allElements function is implemented as a recursive function, which is more idiomatic in Idris.

  6. In the main function, we demonstrate both inferred and explicit type usage for generic functions.

  7. Idris uses putStrLn for printing to the console, similar to Go’s fmt.Println.

Note that Idris is a purely functional language with dependent types, which makes it quite different from Go in many aspects. This example demonstrates similar concepts, but the underlying paradigm and type system are more advanced in Idris.