I'm struggling how to figure out how to write proofs that aren't super super long. In particular, my current workflow is to write a bunch of have statements and then rewrite using them. This matches my mental model of how I think about how I would prove something on paper--in particular the have statements seem to be nice for communicating a proof to a human. However, they get quite cumbersome and people who answer my questions here (thanks again, especially @Adam Topaz ) seem to be able to prove things more efficiently. Or at least, they know how to golf all of the have statements away.
A good example is the following lemma, part of proving that a monoid object in the category of types is a monoid:
importcategory_theory.closed.cartesianimportcategory_theory.limits.has_limitsimportcategory_theory.monoidal.Mon_importcategory_theory.limits.typesimportcategory_theory.limits.shapes.typesimportcategory_theory.types-- set_option pp.universes true-- set_option pp.implicit true-- set_option trace.simplify.rewrite truenoncomputable theoryuniversesuvopencategory_theoryopencategory_theory.limits.typesopencategory_theory.concrete_categoryinstance:monoidal_category(Typeu):=monoidal_of_has_finite_products(Typeu)instancehas_one_of_Mon__Type(M:Mon_(Typeu)):has_oneM.X:={one:=((terminal_iso.symm.hom≫M.one)punit.star)}instancehas_mul_of_Mon__Type(M:Mon_(Typeu)):has_mulM.X:={mul:=(λab,((binary_product_iso__).symm.hom≫M.mul)(a,b))}@[simp, reassoc]lemmabinary_product_iso_limits_fst_eq_fst(AB:Typeu):(binary_product_isoAB).inv≫limits.prod.fst=prod.fst:=limits.prod.lift_fst__@[simp, reassoc]lemmabinary_product_iso_limits_snd_eq_snd(AB:Typeu):(binary_product_isoAB).inv≫limits.prod.snd=prod.snd:=limits.prod.lift_snd__defpunit_prod_iso(A:Typeu):(punit:(Typeu))×A≅A:=(binary_product_iso__).symm≪≫tensor_isoterminal_iso.symm(iso.refl_)≪≫(λ_A)defpunit_morph_prod(M:Mon_(Typeu)):(punit:Typeu)×M.X⟶M.X×M.X:=(binary_product_iso__).symm.hom≫(tensor_isoterminal_iso.symm(iso.refl_)).hom≫(M.one⊗(𝟙M.X))≫(binary_product_iso__).homlemmaprod_map_bpo_commutes(ABCD:Typeu)(f:A⟶C)(g:B⟶D):as_hom(prod.mapfg)≫(binary_product_isoCD).inv=(binary_product_isoAB).inv≫limits.prod.mapfg:=by{ext1;simpa}lemmarearrange_comp(abcde:Typeu)(f:a⟶b)(g:b⟶c)(h:c⟶d)(j:d⟶e):(f≫g)≫h≫j=(f≫(g≫h))≫j:=bysimplemmarearrange_comp_2(abcde:Typeu)(f:a⟶b)(g:b⟶c)(h:c⟶d)(j:d⟶e):(f≫g≫h)≫j=(f≫g)≫h≫j:=bysimplemmaone_mul_of_Mon__Type(M:Mon_(Typeu)):∀(a:M.X),1*a=a:=beginhavemul:=M.mul,letom:=M.one_mul,introa,havemorph_one_a:(prod.map(terminal_iso.symm.hom≫M.one)(𝟙M.X))(punit.star,a)=((terminal_iso.symm.hom≫M.one)punit.star,a),bysimp,havemorph_one_comp_a:(as_hom(prod.mapterminal_iso.inv(𝟙M.X))≫as_hom(prod.mapM.one(𝟙M.X)))(punit.star,a)=((terminal_iso.symm.hom≫M.one)punit.star,a),beginsimponly[category_theory.types_comp_apply,category_theory.iso.symm_hom],refl,end,havecomm_rectangle_terminal_iso:as_hom(prod.map(terminal_iso.inv)(𝟙M.X))≫(binary_product_iso__).symm.hom=(binary_product_iso__).symm.hom≫((terminal_iso.symm.hom)⊗(𝟙M.X)),-- you have to have the outer parensby{simp,applyprod_map_bpo_commutes},havecomm_rectangle_prod_map:as_hom(prod.mapM.one(𝟙M.X))≫(binary_product_iso__).symm.hom=(binary_product_iso__).symm.hom≫(M.one⊗(𝟙M.X)),-- you have to have the outer parensby{simp,applyprod_map_bpo_commutes},haverearrange_composition:(as_hom(prod.mapterminal_iso.inv(𝟙M.X))≫as_hom(prod.mapM.one(𝟙M.X)))≫(binary_product_isoM.XM.X).symm.hom≫M.mul=(as_hom(prod.mapterminal_iso.inv(𝟙M.X))≫(as_hom(prod.mapM.one(𝟙M.X))≫(binary_product_isoM.XM.X).symm.hom))≫M.mul,beginbyapplyrearrange_comp,-- simp,-- `simp` should work here, at the time of writing this comment it seems to time outend,haverearrange_composition_2:((as_hom(prod.mapterminal_iso.inv(𝟙M.X))≫(binary_product_iso(𝟙_(Typeu))M.X).symm.hom≫(M.one⊗𝟙M.X))≫M.mul)=(as_hom(prod.mapterminal_iso.inv(𝟙M.X))≫(binary_product_iso(𝟙_(Typeu))M.X).symm.hom)≫(M.one⊗𝟙M.X)≫M.mul,byapplyrearrange_comp_2,havesame_morphism:(binary_product_iso(⊤_Typeu)M.X).symm.hom=(binary_product_iso(𝟙_(Typeu))M.X).symm.hom,byrefl,haveppo_equality:(((binary_product_isopunitM.X).symm.hom≫(terminal_iso.symm.hom⊗𝟙M.X))≫(λ_M.X).hom)=prod.snd,bysimp,unfoldhas_mul.mul,unfoldhas_one.one,rw[←morph_one_comp_a],rw[←(types_comp_apply(as_hom(prod.mapterminal_iso.inv(𝟙M.X))≫as_hom(prod.mapM.one(𝟙M.X)))((binary_product_isoM.XM.X).symm.hom≫M.mul))],rw[rearrange_composition],rw[comm_rectangle_prod_map],rw[rearrange_composition_2],rw[←same_morphism],rw[comm_rectangle_terminal_iso],rw[om],rw[ppo_equality],end
Each of the have statements/auxillary lemmas pretty much comes down to simp. Does anyone have any tips and tricks on how one golfs such a proof?
I know that the proof "is just M.one_mul", so I first applied a into M.one_mul (by composing with binary_product_iso and using congr_fun.
I applied simp on both the goal and the hypothesis obtained, and see what I have. In this case the hypothesis already looks like the goal, so I used convert.
In the lhs, the two elements (in limits.prod _ _) are equal since the components are (this is usually done by ext). I moved into prod since the extlemmas there looks better.
Apply simp again. The only barrier seems to be limits.prod.fst (limits.prod.map foo) so the elementwise_of versions of them are provided. simp then closes the goal.