10

In Haskell, I might write a typeclass with a type declaration to create a type family, like so:

class ListLike k where
    type Elem ::  * -> *
    fromList :: [Elem k] -> k

And then write instances like this:

instance ListLike [a] where
    type Elem [a] = a
    fromList = id

instance ListLike Bytestring where
    type Elem Bytestring = Char
    fromList = pack

I'm aware that you can create typeclasses and type-level functions in Idris, but the methods operate on data of the given type, not the type itself.

How can I make a typeclass-constrained type family in Idris like the one above?

AJF
  • 11,767
  • 2
  • 37
  • 64
  • 3
    I think you don't need this - remember you have even better tools: [first class types](http://docs.idris-lang.org/en/latest/tutorial/typesfuns.html#first-class-types) - so you can write `Elem` as a function – Random Dev Jun 03 '15 at 12:29
  • @Carsten I realise that, but how might I constrain that function to instances of that typeclass? – AJF Jun 03 '15 at 14:40
  • 1
    I think you probably don't have a problem with associated type families at all. Idris does not, however, offer associated *data* families, and I don't know if that will keep you from doing something or other. It also doesn't have Haskell-style non-associated type families; there is no pattern matching whatsoever on type constructors. – dfeuer Jun 03 '15 at 15:24

1 Answers1

8

I have no clue if you will ever find a use for this, but I think the obvious translation should be

class ListLike k where
    llElem : Type
    fromList : List llElem -> k

instance ListLike (List a) where
    llElem = a
    fromList = id

instance ListLike (Maybe a) where
  llElem = a
  fromList [] = Nothing
  fromList (a::_) = Just a

usage

λΠ> the (Maybe Int) (fromList [3])
Just 3 : Maybe Int
λΠ> the (List Int) (fromList [3])
[3] : List Int
Random Dev
  • 51,810
  • 9
  • 92
  • 119
  • 1
    I might ask, why isn't `llElem : Type -> Type` rather than `Type`? Surely it's an undecidable instance? – AJF Jun 03 '15 at 16:42
  • 1
    load it into idris and have a look at the types (`:t`) - you can get almost the same in Haskell with `data` instead of `type` inside your family - `llElem` is `ListLike k => Type` so it makes sense in `ListLike k => List llElem -> k` and you don't really need/want more here (or so I guess) – Random Dev Jun 03 '15 at 17:04
  • 1
    another way to do it in Haskell would be with a two param type class and [functional dependencies](https://wiki.haskell.org/Functional_dependencies) - the important fact is that `k`implies `llElem` – Random Dev Jun 03 '15 at 17:05
  • 2
    @AJFarmar `llElem` can't be used on its own, but the appropriate instance can be determined from the use of `fromList`. Idris doesn't actually check this at the moment in the definition of this class (but it should and will soon). – Edwin Brady Jun 04 '15 at 07:22
  • For me Idris 0.9.18 reports 3 errors for the given code `DecEq.idr:1:7:When elaborating type of Main.fromList: Can't resolve type class ListLike k DecEq.idr:5:10:ListLike is not a type class DecEq.idr:9:10:ListLike is not a type class` – Boldizsár Németh Jul 12 '15 at 17:41