12

In Haskell, functions are functors and the following code works as expected:

(*3) `fmap` (+100) $ 1

The output is 303 of course. However, in Idris (with fmap -> map), it gives the following error:

Can't find implementation for Functor (\uv => Integer -> uv)

To me this seems like functions aren't implemented as functors in Idris, at least not like they are in Haskell, but why is that?

Furthermore, what exactly does the type signature (\uv => Integer -> uv) mean? It looks like some partially applied function, and that's what would be expected from a functor implementation, but the syntax is a bit confusing, specifically what \ which is supposed to be used for a lambda/literal is doing there.

corazza
  • 31,222
  • 37
  • 115
  • 186
  • 2
    I'm not an Idris expert, but it should be the eta-expanded version of `(->) Integer`. Here, `(->)` is partially applied, but in `\uv => (->) Integer uv` it is fully applied. Both are eta-convertible. – chi May 09 '18 at 18:33
  • @chi ah right that makes sense. thanks. I think it confused me because I don't interpret types as first-order intuitively yet – corazza May 09 '18 at 18:40
  • Is it due to Idris functions being total? I don't know Idris well enough to come up with a good example, but it seems like the composition of two total functions is not, itself, guaranteed to be total. (My first try was something like `(10.0 /) . (10.0 - )`, although that function applied to 10 evaluates to `Infinity`.) – chepner May 09 '18 at 18:40
  • @chepner I could be wrong but I don't think Idris is a total language. It's turing-complete, and for example isn't `10.0 /` not total itself? – corazza May 09 '18 at 18:51
  • Well, `(10.0 /)` *is* total, since it maps `10.0` to `Infinity`. `(.)` is marked as total, but my glancing familiarity with Idris makes it difficult for me to come up with a good example of a partial function. – chepner May 09 '18 at 19:03
  • @chepner oh! I tried it with `log (-1)` but that turns out to be NaN. cheating!:p – corazza May 09 '18 at 19:05
  • I thought maybe I could do something with `Prelude.Nat.(-)`, but it uses dependent typing to make that total as well. – chepner May 09 '18 at 19:10
  • Oh, it looks likes it's just a matter of syntax, not semantics: https://groups.google.com/forum/#!topic/idris-lang/f7iSKzKBF1A. TL;DR `(->)` isn't a type constructor. – chepner May 09 '18 at 19:12
  • [This](https://stackoverflow.com/q/32043985/2747511) is related. – Anton Trunov May 09 '18 at 19:31
  • 4
    @chepner The composition of two total functions is total, if it is well-typed at all. – Daniel Wagner May 10 '18 at 03:51
  • FWIW, I sometimes think we would be better off in Haskell without `Functor (->)` too. Shorthands involving this instance are often confusing and would be better expressed with `Arrow` combinators, whereas for serious larger-scale uses of the `Monad` instance it's better to use the more explicit `Reader` type. – leftaroundabout May 10 '18 at 10:43

1 Answers1

5

Functor is an interface. In Idris, implementations are restricted to data or type constructors, i.e. defined using the data keyword. I am not an expert in dependent types, but I believe this restriction is required—practically, at least—for a sound interface system.

When you ask for the type of \a => Integer -> a at the REPL, you get

\a => Integer -> a : Type -> Type

In Haskell we would consider this to be a real type constructor, one that can be made into an instance of type classes such as Functor. In Idris however, (->) is not a type constructor but a binder.

The closest thing to your example in Idris would be

((*3) `map` Mor (+100)) `applyMor` 1

using the Data.Morphisms module. Or step by step:

import Data.Morphisms

f : Morphism Integer Integer
f = Mor (+100)

g : Morphism Integer Integer
g = (*3) `map` f

result : Integer
result = g `applyMor` 1

This works because Morphism is a real type constructor, with a Functor implementation defined in the library.

joel
  • 6,359
  • 2
  • 30
  • 55
Jeroen Noels
  • 341
  • 2
  • 8