Zulip Chat Archive
Stream: new members
Topic: Coercions using additional type parameters
Plamen Dimitrov (Sep 18 2025 at 16:40):
I have the following structures
namespace Bin
...
abbrev Binary := List Bit
end Bin
namespace Bool
def Binary (C : ℕ) : Type := { enc : Bin.Binary // List.length enc = C }
end Bool
namespace Count
/-- Custom binary type with both value and weight. -/
structure Binary where
val : Bin.Binary
weight : ℕ
instance : Coe Binary Bin.Binary := ⟨fun x => x.val⟩
end Count
namespace Relative
/-- Custom C-length binary type with both value and weight. -/
structure Binary (C : ℕ) where
val : Bool.Binary C
weight : ℕ
instance : Coe (Binary 4) Count.Binary := ⟨fun x => { val := x.val.val, weight := x.weight }⟩
end Relative
Why for the final coercion I cannot use
instance : Coe (Binary C) Count.Binary := ⟨fun x => { val := x.val.val, weight := x.weight }⟩
which would instead lead to
instance does not provide concrete values for (semi-)out-params
Coe (Binary ?C)
A similar coercion will work if the input and output type both contain the C parameter for instance. I clearly cannot list all of the possible C values and I need the typeclass-based coercions in situation where an explicit one won't do.
Aaron Liu (Sep 18 2025 at 16:55):
Plamen Dimitrov (Sep 19 2025 at 03:38):
Thank you @Aaron Liu, interesting that the various LLMs I tried with all of their verbosity could not have suggested that the Coe being 2-way coercion is the cause of this and one way like this would fix it.
Plamen Dimitrov (Sep 23 2025 at 15:32):
Looking at simpler case here like
import Mathlib
inductive Bit : Type
| zero : Bit
| one : Bit
deriving DecidableEq
abbrev Binary := List Bit
def CBinary (C : ℕ) : Type := { enc : Binary // List.length enc = C }
instance : CoeOut (CBinary C) Binary := ⟨fun x => x.val⟩
def print (b : Binary) : String := b.foldr (fun bit acc => if bit == Bit.one then "1" ++ acc else "0" ++ acc) ""
instance : BooleanAlgebra (CBinary C) := sorry
def literal_encoding4 : CBinary 4 := { val := [Bit.zero, Bit.one, Bit.zero, Bit.one], property := by decide }
#eval print literal_encoding4
#eval print (literal_encoding4 ⊓ literal_encoding4).val
it seems like I cannot use #eval print (literal_encoding4 ⊓ literal_encoding4) instead as the last line since the coercion would not work with the ⊓ meet, isn't the ⊓ interpret simply as a bi-argument function that should then apply automatically to make use of the explicit coercion defined above?
Plamen Dimitrov (Sep 23 2025 at 15:33):
All of this is assuming a BooleanAlgebra instance proof that I have omitted here for brevity and the fact that `literal_encoding4 ⊓ literal_encoding4 : CBinary C already where the coercion is defined.
Aaron Liu (Sep 23 2025 at 15:57):
The types are propagated "outside-in" so since print expects a Binary it tries to find a way to do inf on Binary and fails
Plamen Dimitrov (Sep 23 2025 at 17:23):
Is there any way to make to work around this outside-in order then? Override the order via brackets or some other way to tell Lean how to process this?
Jovan Gerbscheid (Sep 23 2025 at 21:49):
You can write print (literal_encoding4 ⊓ literal_encoding4:). Writing ( ... :) is a way to tell lean to elaborate that expression without an expected type. It is mostly the same as (... : _). You can also give the expected type explicitly as print (literal_encoding4 ⊓ literal_encoding4 : CBinary 4)
Plamen Dimitrov (Sep 25 2025 at 05:45):
Thank you, the "smiley face" worked splendidly and preserves as much of the coercion automation as possible with a minimum extra typing overhead.
Last updated: Dec 20 2025 at 21:32 UTC