10

I'm trying to define a function named byteWidth, which captures the usage about "get byte width of specific atomic type".


My 1st trial:

byteWidth : Type -> Int
byteWidth Int = 8
byteWidth Char = 1

And the Idris compiler complains: "When checking left hand side of byteWidth: No explicit types on left hand side: Int"


My 2nd trial:

interface BW a where
  byteWidth : a -> Int

implementation BW Int where
  byteWidth _ = 8

implementation BW Char where
  byteWidth _ = 1

And in this case, I can only use byteWidth like byteWidth 'a' but not byteWidth Char.

luochen1990
  • 3,689
  • 1
  • 22
  • 37

2 Answers2

10

Your second attempt was really close to the principled solution. As you've observed the problem is that you can't take the type a as an argument when implementing BW a. But you don't care as you can always set an implicit argument explicitly later on.

This gives us:

interface BW a where
  byteWidth_ : Int

implementation BW Int where
  byteWidth_ = 8

implementation BW Char where
  byteWidth_= 1

And you can then recover the type you wanted by partially applying byteWidth_ like so:

byteWidth : (a : Type) -> BW a => Int
byteWidth a = byteWidth_ {a}
gallais
  • 11,823
  • 2
  • 30
  • 63
  • This works, but too tricky... I still think that my solution is better... – luochen1990 Feb 02 '18 at 09:41
  • Your solution uses `{auto pr : _}` which is an anti-pattern – gallais Feb 02 '18 at 13:51
  • thanks for point out that, but I can't understand why it is an anti-pattern, any more detail or example, or some reference? – luochen1990 Feb 03 '18 at 12:03
  • 2
    It's a way to get the system to randomly guess some proofs (up to a certain depth) and because it's way too easy to use, people are abusing it instead of proving their problem decidable or using more principled search strategies (e.g. type classes which this questions is essentially about). – gallais Feb 03 '18 at 21:18
  • 2
    A type class is intrinsically an *open* way of solving a problem: you can add new instances later on when you realise you need them. With the singleton + auto approach, only the person who has control over the original library can add new cases. It's anti-modular. – gallais Feb 03 '18 at 21:24
  • Thanks for your explaining, it's very clear and helpful ! – luochen1990 Feb 07 '18 at 05:44
2

In Idris, you can not pattern match a type, and suppose you can, it's not possible for anybody to enumerate all possible types, so it can't be total.

The only extra thing you need is a proof about the type a is inside some specific set, and we name this proposition as ByteWidthAvailable.

data ByteWidthAvailable : Type -> Type where
  IntBWA : ByteWidthAvailable Int
  ChaBWA : ByteWidthAvailable Char

total
byteWidth : (a : Type) -> {auto prf: ByteWidthAvailable a} -> Int
byteWidth _ {prf = IntBWA} = 8
byteWidth _ {prf = ChaBWA} = 1

The only trick here is the auto command provided by Idris, which helps to generate a proof automaticly at call-site, so that you can call byteWidth like byteWidth Char instead of byteWidth Char {prf = ChaBWA}.

luochen1990
  • 3,689
  • 1
  • 22
  • 37