typeclass https://www.e-learn.cn/tag/typeclass zh-hans In scala, how to make type class working for Aux pattern? - Part 2 https://www.e-learn.cn/topic/4115956 <span>In scala, how to make type class working for Aux pattern? - Part 2</span> <span><span lang="" about="/user/217" typeof="schema:Person" property="schema:name" datatype="">随声附和</span></span> <span>2021-02-19 03:46:28</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>This is a follow up question of: In scala, how to make type class working for Aux pattern?</p> <p>Considering the following example:</p> <pre class="lang-scala prettyprint-override"><code> trait Base { type Out def v: Out } object Base { type Aux[T] = Base { type Out = T } type Lt[T] = Base { type Out &lt;: T } class ForH() extends Base { final type Out = HNil override def v: Out = HNil } object ForH extends ForH } trait TypeClasses { class TypeClass[B] def summon[B](b: B)(implicit ev: TypeClass[B]): TypeClass[B] = ev } object T1 extends TypeClasses { implicit def t1: TypeClass[Base.Aux[HNil]] = new TypeClass[Base.Aux[HNil]] implicit def t2: TypeClass[Int] = new TypeClass[Int] } object T2 extends TypeClasses { implicit def t1[T &lt;: Base.Aux[HNil]]: TypeClass[T] = new TypeClass[T] } object T3 extends TypeClasses { implicit def t1[ H &lt;: HList, T &lt;: Base.Lt[H] ]: TypeClass[T] = new TypeClass[T] { type HH = H } } object T4 extends TypeClasses { implicit def t1[ H &lt;: HList, T &lt;: Base.Aux[H] ]: TypeClass[T] = new TypeClass[T] { type HH = H } } it("No Aux") { val v = 2 T1.summon(v) // works } it("Aux1") { val v = new Base.ForH() T1.summon(v) // oops T1.summon(Base.ForH) // oops val v2 = new Base.ForH(): Base.Aux[HNil] T1.summon(v2) // works! } it("Aux2") { val v = new Base.ForH() T2.summon(v) // works T2.summon(Base.ForH) // works val v2 = new Base.ForH(): Base.Aux[HNil] T2.summon(v2) // works } it("Aux3") { val v = new Base.ForH() T3.summon(v) // oops T3.summon(Base.ForH) // oops val v2 = new Base.ForH(): Base.Aux[HNil] T3.summon(v2) // oops } it("Aux4") { val v = new Base.ForH() T4.summon(v) // oops T4.summon(Base.ForH) // oops val v2 = new Base.ForH(): Base.Aux[HNil] T4.summon(v2) // oops } </code></pre> <p>all implementations of <code>TypeClasses</code> contains an implicit scope of their underlying <code>TypeClass</code>, among them, the <code>T1</code> is the most simple and specific definition for <code>ForH</code>, unfortunately it doesn't work. An improvement was proposed by @Dan Simon (in <code>T2</code>), it uses a type parameter to allow the spark compiler to discover <code>ForH &lt;:&lt; Base.Aux[HNil]</code></p> <p>Now imagine that I'd like to extend @Dan Simon's solution, such that the type class applies to all classes like <code>ForH</code> for different kinds of HList (a super trait of HNil). 2 natural extensions are in <code>T3</code> &amp; <code>T4</code> respectively.</p> <p>Unfortunately none of them works. The <code>T4</code> can be explained by the fact that <code>ForH &lt;:&lt; Aux[HList]</code> is invalid, but <code>T3</code> can't use this excuse. In addition, there is no way to improve it to compile successfully.</p> <p>Why the type class summoning algorithm failed this case? And what should be done to make the type class pattern actually works?</p> <br /><h3>回答1:</h3><br /><p>Again, <code>T1.summon(v)</code> doesn't compile because <code>T1.t1</code> is not a candidate, manually resolved <code>T1.summon(v)(T1.t1)</code> doesn't compile.</p> <p>For <code>T3</code> and <code>T4</code> <code>T3.t1[HNil, Base.ForH]</code>, <code>T4.t1[HNil, Base.ForH]</code> would be a candidate</p> <pre><code>T3.summon(v)(T3.t1[HNil, Base.ForH]) // compiles T4.summon(v)(T4.t1[HNil, Base.ForH]) // compiles </code></pre> <p>but the trouble is that <code>H</code> is inferred first and it's inferred to be <code>Nothing</code> but <code>t1[Nothing, Base.ForH]</code> doesn't satisfy type bounds.</p> <p>So the trouble is not with implicit resolution algorithm, it's ok, the trouble is with type inference (and all we know that it's pretty weak in Scala).</p> <p>You can prevent <code>H</code> to be inferred too fast as <code>Nothing</code> if you modify <code>T3.t1</code>, <code>T4.t1</code></p> <pre><code>object T3 extends TypeClasses { implicit def t1[ H &lt;: HList, T &lt;: Base/*.Lt[H]*/ ](implicit ev: T &lt;:&lt; Base.Lt[H]): TypeClass[T] = new TypeClass[T] { type HH = H } } object T4 extends TypeClasses { implicit def t1[ H &lt;: HList, T &lt;: Base/*.Aux[H]*/ ](implicit ev: T &lt;:&lt; Base.Aux[H]): TypeClass[T] = new TypeClass[T] { type HH = H } } T3.summon(v) // compiles T4.summon(v) // compiles </code></pre> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/65853961/in-scala-how-to-make-type-class-working-for-aux-pattern-part-2</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/scala" hreflang="zh-hans">scala</a></div> <div class="field--item"><a href="/tag/typeclass" hreflang="zh-hans">typeclass</a></div> <div class="field--item"><a href="/tag/abstract-data-type" hreflang="zh-hans">abstract-data-type</a></div> <div class="field--item"><a href="/tag/type-alias" hreflang="zh-hans">type-alias</a></div> <div class="field--item"><a href="/tag/scala-213" hreflang="zh-hans">scala-2.13</a></div> </div> </div> Thu, 18 Feb 2021 19:46:28 +0000 随声附和 4115956 at https://www.e-learn.cn Any advantage of using type constructors in type classes? https://www.e-learn.cn/topic/4114603 <span>Any advantage of using type constructors in type classes?</span> <span><span lang="" about="/user/191" typeof="schema:Person" property="schema:name" datatype="">末鹿安然</span></span> <span>2021-02-18 22:01:16</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>Take for example the class <code>Functor</code>:</p> <pre><code>class Functor a instance Functor Maybe </code></pre> <p>Here <code>Maybe</code> is a type constructor.</p> <p>But we can do this in two other ways:</p> <p>Firstly, using multi-parameter type classes:</p> <pre><code>class MultiFunctor a e instance MultiFunctor (Maybe a) a </code></pre> <p>Secondly using type families:</p> <pre><code>class MonoFunctor a instance MonoFunctor (Maybe a) type family Element type instance Element (Maybe a) a </code></pre> <p>Now there's one obvious advantage of the two latter methods, namely that it allows us to do things like this:</p> <pre><code>instance Text Char </code></pre> <p>Or:</p> <pre><code>instance Text type instance Element Text Char </code></pre> <p>So we can work with monomorphic containers.</p> <p>The second advantage is that we can make instances of types that don't have the type parameter as the final parameter. Lets say we make an <code>Either</code> style type but put the types the wrong way around:</p> <pre><code>data Silly t errorT = Silly t errorT instance Functor Silly -- oh no we can't do this without a newtype wrapper </code></pre> <p>Whereas</p> <pre><code>instance MultiFunctor (Silly t errorT) t </code></pre> <p>works fine and</p> <pre><code>instance MonoFunctor (Silly t errorT) type instance Element (Silly t errorT) t </code></pre> <p>is also good.</p> <p>Given these flexibility advantages of only using complete types (not type signatures) in type class definitions, is there any reason to use the original style definition, assuming you're using GHC and don't mind using the extensions? That is, is there anything special you can do putting a type constructor, not just a full type in a type class that you can't do with multi-parameter type classes or type families?</p> <br /><h3>回答1:</h3><br /><p>Your proposals ignore some rather important details about the existing <code>Functor</code> definition because you didn't work through the details of writing out what would happen with the class's member function.</p> <pre><code>class MultiFunctor a e where mfmap :: (e -&gt; ??) -&gt; a -&gt; ???? instance MultiFunctor (Maybe a) a where mfmap = ??????? </code></pre> <p>An important property of <code>fmap</code> at the moment is that its first argument can change types. <code>fmap show :: (Functor f, Show a) =&gt; f a -&gt; f String</code>. You can't just throw that away, or you lose most of the value of <code>fmap</code>. So really, <code>MultiFunctor</code> would need to look more like...</p> <pre><code>class MultiFunctor s t a b | s -&gt; a, t -&gt; b, s b -&gt; t, t a -&gt; s where mfmap :: (a -&gt; b) -&gt; s -&gt; t instance (a ~ c, b ~ d) =&gt; MultiFunctor (Maybe a) (Maybe b) c d where mfmap _ Nothing = Nothing mfmap f (Just a) = Just (f a) </code></pre> <p>Note just how incredibly complicated this has become to try to make inference at least <em>close</em> to possible. All the functional dependencies are in place to allow instance selection without annotating types all over the place. (I may have missed a couple possible functional dependencies in there!) The instance itself grew some crazy type equality constraints to allow instance selection to be more reliable. And the worst part is - this still has worse properties for reasoning than <code>fmap</code> does.</p> <p>Supposing my previous instance didn't exist, I could write an instance like this:</p> <pre><code>instance MultiFunctor (Maybe Int) (Maybe Int) Int Int where mfmap _ Nothing = Nothing mfmap f (Just a) = Just (if f a == a then a else f a * 2) </code></pre> <p>This is broken, of course - but it's broken in a new way that wasn't even possible before. A <em>really</em> important part of the definition of <code>Functor</code> is that the types <code>a</code> and <code>b</code> in <code>fmap</code> don't appear anywhere in the instance definition. Just looking at the class is enough to tell the programmer that the behavior of <code>fmap</code> <em>cannot</em> depend on the types <code>a</code> and <code>b</code>. You get that guarantee for free. You don't need to trust that instances were written correctly.</p> <p>Because <code>fmap</code> gives you that guarantee for free, you don't even need to check both <code>Functor</code> laws when defining an instance. It's sufficient to check the law <code>fmap id x == x</code>. The second law comes along for free when the first law is proven. But with that broken <code>mfmap</code> I just provided, <code>mfmap id x == x</code> is true, even though the second law is not.</p> <p>As the implementer of <code>mfmap</code>, you have more work to do to prove your implementation is correct. As a user of it, you have to put more trust in the implementation's correctness, since the type system can't guarantee as much.</p> <p>If you work out more complete examples for the other systems, you find that they have just as many issues if you want to support the full functionality of <code>fmap</code>. And this is why they aren't really used. They add a <em>lot</em> of complexity for only a small gain in utility.</p> <br /><br /><br /><h3>回答2:</h3><br /><p>Well, for one thing the traditional functor class is just much simpler. That alone is a valid reason to prefer it, even though this is Haskell and not Python. And it also represents the mathematical idea better of what a functor is supposed to be: a mapping from objects to objects (<code>f :: *-&gt;*</code>), with extra property (<code>-&gt;Constraint</code>) that each (<code>forall (a::*) (b::*)</code>) morphism (<code>a-&gt;b</code>) is lifted to a morphism on the corresponding object mapped to (<code>-&gt; f a-&gt;f b</code>). <br />None of that can be seen very clearly in the <code>* -&gt; * -&gt; Constraint</code> version of the class, or its TypeFamilies equivalent.</p> <p>On a more practical account, yes, there are also things you can only do with the <code>(*-&gt;*)-&gt;Constraint</code> version.</p> <p>In particular, what this constraint guarantees you right away is that <em>all</em> Haskell types are valid objects you can put into the functor, whereas for <code>MultiFunctor</code> you need to check every possible contained type, one by one. Sometimes that's just not possible (or is it?), like when you're mapping over infinitely many types:</p> <pre><code>data Tough f a = Doable (f a) | Tough (f (Tough f (a, a))) instance (Applicative f) = Semigroup (Tough f a) where Doable x &lt;&gt; Doable y = Tough . Doable $ (,)&lt;$&gt;x&lt;*&gt;y Tough xs &lt;&gt; Tough ys = Tough $ xs &lt;&gt; ys -- The following actually violates the semigroup associativity law. Hardly matters here I suppose... xs &lt;&gt; Doable y = xs &lt;&gt; Tough (Doable $ fmap twice y) Doable x &lt;&gt; ys = Tough (Doable $ fmap twice x) &lt;&gt; ys twice x = (x,x) </code></pre> <p>Note that this uses the <code>Applicative</code> instance of <code>f</code> not just on the <code>a</code> type, but also on arbitrary tuples thereof. I can't see how you could express that with a <code>MultiParamTypeClasses</code>- or <code>TypeFamilies</code>-based applicative class. (It might be possible if you make <code>Tough</code> a suitable GADT, but without that... probably not.)</p> <p>BTW, this example is perhaps not as useless as it may look – it basically expresses read-only vectors of length 2<sup><em>n</em></sup> in a monadic state.</p> <br /><br /><br /><h3>回答3:</h3><br /><p>The expanded variant is indeed more flexible. It was used e.g. by Oleg Kiselyov to define restricted monads. Roughly, you can have</p> <pre><code> class MN2 m a where ret2 :: a -&gt; m a class (MN2 m a, MN2 m b) =&gt; MN3 m a b where bind2 :: m a -&gt; (a -&gt; m b) -&gt; m b </code></pre> <p>allowing monad instances to be parametrized over <code>a</code> and <code>b</code>. This is useful because you can restrict those types to members of some other class:</p> <pre><code>import Data.Set as Set instance MN2 Set.Set a where -- does not require Ord return = Set.singleton instance Prelude.Ord b =&gt; MN3 SMPlus a b where -- Set.union requires Ord m &gt;&gt;= f = Set.fold (Set.union . f) Set.empty m </code></pre> <p>Note than because of that <code>Ord</code> constraint, we are unable to define <code>Monad Set.Set</code> using unrestricted monads. Indeed, the monad class requires the monad to be usable at all types.</p> <p>Also see: parameterized (indexed) monad.</p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/29463811/any-advantage-of-using-type-constructors-in-type-classes</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/haskell" hreflang="zh-hans">haskell</a></div> <div class="field--item"><a href="/tag/typeclass" hreflang="zh-hans">typeclass</a></div> </div> </div> Thu, 18 Feb 2021 14:01:16 +0000 末鹿安然 4114603 at https://www.e-learn.cn Lift instance of class with a `MonadIO` type-variable to the transformed monad https://www.e-learn.cn/topic/4093696 <span>Lift instance of class with a `MonadIO` type-variable to the transformed monad</span> <span><span lang="" about="/user/124" typeof="schema:Person" property="schema:name" datatype="">ⅰ亾dé卋堺</span></span> <span>2021-02-11 06:37:12</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>As part of a program where I need to log data from monadic computations, I am trying to define a class to make this more convenient.</p> <pre><code>module Serial where import Data.Int import Data.IORef import System.IO import Control.Monad.Trans import Foreign.Ptr import Foreign.Marshal import Foreign.Storable class MonadIO m =&gt; Serial m a where get :: Handle -&gt; m a put :: Handle -&gt; a -&gt; m () </code></pre> <p>One of the things I'd like to be able to do is to define <code>get</code> and <code>put</code> in a 'higher' monad, since some data is inaccessible in <code>IO</code>. For simpler data, like instances of <code>Storable</code>, for example, <code>IO</code> is enough. I'd like to keep the basic instances in the 'lowest' possible monad, but allow the actions to be lifted to any 'higher' <code>MonadIO</code> instance.</p> <pre><code>instance (Serial m a, MonadIO (t m), MonadTrans t) =&gt; Serial (t m) a where get = lift . get put h = lift . put h instance Storable a =&gt; Serial IO a where get h = alloca (\ptr -&gt; hGetBuf h ptr (sizeOf (undefined :: a)) &gt;&gt; peek ptr) put h a = with a (\ptr -&gt; hPutBuf h ptr $ sizeOf a) </code></pre> <p>The idea is to enable functions like</p> <pre><code>func :: Serial m a =&gt; Handle -&gt; a -&gt; m () func h a = put h (0::Int32) &gt;&gt; put h a </code></pre> <p>where an instance in <code>IO</code> can be combined with an instance in any <code>MonadIO</code>. However with my current code, GHC cannot deduce the instance for <code>Serial m Int32</code>. For the particular case of lifting <code>IO</code> this problem can be solved by <code>liftIO</code>, but if the base type is <code>t IO</code> that doesn't work anymore. I think this can be solved by overlapping instances, but I would like to avoid that if possible. Is there any way to achieve this?</p> <br /><h3>回答1:</h3><br /><p>You can just write out the required extra constraint:</p> <pre><code>func :: (Serial m a, Serial m Int32) =&gt; Handle -&gt; a -&gt; m () func h a = put h (0::Int32) &gt;&gt; put h a </code></pre> <p>(I think this requires <code>-XFlexibleContexts</code>.)</p> <p>If this makes the signatures unwieldy, you can group together constraints in a “constraint synonym class”:</p> <pre><code>class (Serial m a, Serial m Int32, Serial m Int64, ...) =&gt; StoSerial m a instance (Serial m a, Serial m Int32, Serial m Int64, ...) =&gt; StoSerial m a func :: StoSerial m a =&gt; Handle -&gt; a -&gt; m () func h a = put h (0::Int32) &gt;&gt; put h a </code></pre> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/64184067/lift-instance-of-class-with-a-monadio-type-variable-to-the-transformed-monad</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/haskell" hreflang="zh-hans">haskell</a></div> <div class="field--item"><a href="/tag/typeclass" hreflang="zh-hans">typeclass</a></div> <div class="field--item"><a href="/tag/monad-transformers" hreflang="zh-hans">monad-transformers</a></div> <div class="field--item"><a href="/tag/lifting" hreflang="zh-hans">lifting</a></div> </div> </div> Wed, 10 Feb 2021 22:37:12 +0000 ⅰ亾dé卋堺 4093696 at https://www.e-learn.cn Lift instance of class with a `MonadIO` type-variable to the transformed monad https://www.e-learn.cn/topic/4093695 <span>Lift instance of class with a `MonadIO` type-variable to the transformed monad</span> <span><span lang="" about="/user/221" typeof="schema:Person" property="schema:name" datatype="">雨燕双飞</span></span> <span>2021-02-11 06:36:49</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>As part of a program where I need to log data from monadic computations, I am trying to define a class to make this more convenient.</p> <pre><code>module Serial where import Data.Int import Data.IORef import System.IO import Control.Monad.Trans import Foreign.Ptr import Foreign.Marshal import Foreign.Storable class MonadIO m =&gt; Serial m a where get :: Handle -&gt; m a put :: Handle -&gt; a -&gt; m () </code></pre> <p>One of the things I'd like to be able to do is to define <code>get</code> and <code>put</code> in a 'higher' monad, since some data is inaccessible in <code>IO</code>. For simpler data, like instances of <code>Storable</code>, for example, <code>IO</code> is enough. I'd like to keep the basic instances in the 'lowest' possible monad, but allow the actions to be lifted to any 'higher' <code>MonadIO</code> instance.</p> <pre><code>instance (Serial m a, MonadIO (t m), MonadTrans t) =&gt; Serial (t m) a where get = lift . get put h = lift . put h instance Storable a =&gt; Serial IO a where get h = alloca (\ptr -&gt; hGetBuf h ptr (sizeOf (undefined :: a)) &gt;&gt; peek ptr) put h a = with a (\ptr -&gt; hPutBuf h ptr $ sizeOf a) </code></pre> <p>The idea is to enable functions like</p> <pre><code>func :: Serial m a =&gt; Handle -&gt; a -&gt; m () func h a = put h (0::Int32) &gt;&gt; put h a </code></pre> <p>where an instance in <code>IO</code> can be combined with an instance in any <code>MonadIO</code>. However with my current code, GHC cannot deduce the instance for <code>Serial m Int32</code>. For the particular case of lifting <code>IO</code> this problem can be solved by <code>liftIO</code>, but if the base type is <code>t IO</code> that doesn't work anymore. I think this can be solved by overlapping instances, but I would like to avoid that if possible. Is there any way to achieve this?</p> <br /><h3>回答1:</h3><br /><p>You can just write out the required extra constraint:</p> <pre><code>func :: (Serial m a, Serial m Int32) =&gt; Handle -&gt; a -&gt; m () func h a = put h (0::Int32) &gt;&gt; put h a </code></pre> <p>(I think this requires <code>-XFlexibleContexts</code>.)</p> <p>If this makes the signatures unwieldy, you can group together constraints in a “constraint synonym class”:</p> <pre><code>class (Serial m a, Serial m Int32, Serial m Int64, ...) =&gt; StoSerial m a instance (Serial m a, Serial m Int32, Serial m Int64, ...) =&gt; StoSerial m a func :: StoSerial m a =&gt; Handle -&gt; a -&gt; m () func h a = put h (0::Int32) &gt;&gt; put h a </code></pre> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/64184067/lift-instance-of-class-with-a-monadio-type-variable-to-the-transformed-monad</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/haskell" hreflang="zh-hans">haskell</a></div> <div class="field--item"><a href="/tag/typeclass" hreflang="zh-hans">typeclass</a></div> <div class="field--item"><a href="/tag/monad-transformers" hreflang="zh-hans">monad-transformers</a></div> <div class="field--item"><a href="/tag/lifting" hreflang="zh-hans">lifting</a></div> </div> </div> Wed, 10 Feb 2021 22:36:49 +0000 雨燕双飞 4093695 at https://www.e-learn.cn How to handle Option with an encoder typeclass in scala https://www.e-learn.cn/topic/4092209 <span>How to handle Option with an encoder typeclass in scala</span> <span><span lang="" about="/user/81" typeof="schema:Person" property="schema:name" datatype="">人盡茶涼</span></span> <span>2021-02-10 22:48:07</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>I have a classic <code>Encoder</code> typeclass.</p> <pre><code>trait Encoder[A] { def encode(a: A): String } </code></pre> <p>I have two questions</p> <p>Question 1 : where does the divergence comes from :</p> <pre><code>[error] … diverging implicit expansion for type sbopt.Test.Encoder[None.type] [error] starting with value stringEncoder in object Test [error] show(None) </code></pre> <pre><code>implicit val stringEncoder = new Encoder[String] { override def encode(a: String): String = a } implicit def optionEncoder[A: Encoder]: Encoder[Option[A]] = (a: Option[A]) =&gt; { val encoderA = implicitly[Encoder[A]] a.fold("")(encoderA.encode) } implicit def someEncoder[A: Encoder]: Encoder[Some[A]] = (a: Some[A]) =&gt; { val encoderA = implicitly[Encoder[A]] encoderA.encode(a.get) } implicit def noneEncoder[A: Encoder]: Encoder[None.type] = (_: None.type) =&gt; "" def show[A: Encoder](a: A) = println(implicitly[Encoder[A]].encode(a)) show(None) </code></pre> <p>Question 2 : I saw in circe that the Encoder is not contravariant. What are the pros and cons ?</p> <pre><code>trait Encoder[-A] { def encode(a: A): String } implicit val stringEncoder: Encoder[String] = (a: String) =&gt; a implicit def optionEncoder[A: Encoder]: Encoder[Option[A]] = (a: Option[A]) =&gt; { val encoderA = implicitly[Encoder[A]] a.fold("")(encoderA.encode) } def show[A: Encoder](a: A) = println(implicitly[Encoder[A]].encode(a)) show(Option("value")) show(Some("value")) show(None) </code></pre> <br /><h3>回答1:</h3><br /><p><strong>Regarding 1.</strong></p> <p>Your definition of <code>noneEncoder</code> is not good. You have an extra context bound (and even extra type parameter).</p> <p>With</p> <pre><code>implicit def noneEncoder/*[A: Encoder]*/: Encoder[None.type] = (_: None.type) =&gt; "" </code></pre> <p>it compiles:</p> <pre><code>show[Option[String]](None) show[None.type](None) show(None) </code></pre> <p>Your original definition of <code>noneEncoder</code> meant that you had an instance of <code>Encoder</code> for <code>None.type</code> provided you had an instance for some <code>A</code> (not constrained i.e. to be inferred). Normally this works if you have the only implicit (or at least the only higher-priority implicit). For example if there were only <code>stringEncoder</code> and original <code>noneEncoder</code> then <code>show[None.type](None)</code> and <code>show(None)</code> would compile.</p> <p><strong>Regarding 2.</strong></p> <p><strong>PROS.</strong> With contravariant <code>Encoder</code></p> <pre><code>trait Encoder[-A] { def encode(a: A): String } </code></pre> <p>you can remove <code>someEncoder</code> and <code>noneEncoder</code>, <code>optionEncoder</code> will be enough</p> <pre><code>show(Some("a")) show[Option[String]](Some("a")) show[Option[String]](None) show[None.type](None) show(None) </code></pre> <p><strong>CONS.</strong> Some people believe that contravariant type classes behave counterintuitively:</p> <p>https://github.com/scala/bug/issues/2509</p> <p>https://groups.google.com/g/scala-language/c/ZE83TvSWpT4/m/YiwJJLZRmlcJ</p> <p>Maybe also relevant: In scala 2.13, how to use implicitly[value singleton type]?</p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/64027726/how-to-handle-option-with-an-encoder-typeclass-in-scala</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/scala" hreflang="zh-hans">scala</a></div> <div class="field--item"><a href="/tag/typeclass" hreflang="zh-hans">typeclass</a></div> <div class="field--item"><a href="/tag/implicit" hreflang="zh-hans">implicit</a></div> </div> </div> Wed, 10 Feb 2021 14:48:07 +0000 人盡茶涼 4092209 at https://www.e-learn.cn What is the correct way to define an already existing (e.g. in Prelude) operator between a user-defined type and an existing type? https://www.e-learn.cn/topic/4083099 <span>What is the correct way to define an already existing (e.g. in Prelude) operator between a user-defined type and an existing type?</span> <span><span lang="" about="/user/123" typeof="schema:Person" property="schema:name" datatype="">我与影子孤独终老i</span></span> <span>2021-02-09 09:22:49</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>Suppose I have a custom type wrapping an existing type,</p> <pre class="lang-hs prettyprint-override"><code>newtype T = T Int deriving Show </code></pre> <p>and suppose I want to be able to add up <code>T</code>s, and that adding them up should result in adding the wrapped values up; I would do this via</p> <pre class="lang-hs prettyprint-override"><code>instance Num T where (T t1) + (T t2) = T (t1 + t2) -- all other Num's methods = undefined </code></pre> <p>I think we are good so far. Please, tell me if there are major concerns up to this point.</p> <p>Now let's suppose that I want to be able to multiply a <code>T</code> by an <code>Int</code> and that the result should be a <code>T</code> whose wrapping value is the former multiplied by the int; I would go for something like this:</p> <pre class="lang-hs prettyprint-override"><code>instance Num T where (T t1) + (T t2) = T (t1 + t2) (T t) * k = T (t * k) -- all other Num's methods = undefined </code></pre> <p>which obviously doesn't work because <code>class Num</code> declares <code>(*) :: a -&gt; a -&gt; a</code>, thus requiring the two operands (and the result) to be all of the same type.</p> <p>Even defining <code>(*)</code> as a free function poses a similar problem (i.e. <code>(*)</code> exists already in <code>Prelude</code>).</p> <p>How could I deal with this?</p> <p>As for the why of this question, I can device the following</p> <ul><li>in my program I want to use <code>(Int,Int)</code> for 2D vectors in a cartesian plane,</li> <li>but I also use <code>(Int,Int)</code> for another unrelated thing,</li> <li>therefore I have to disambiguate between the two, by using a <code>newtype</code> for at least one of them or, if use <code>(Int,Int)</code> for several other reasons, then why not making all of them <code>newtype</code>s wrapping <code>(Int,Int)</code>?</li> <li>since <code>newtype Vec2D = Vec2D (Int,Int)</code> represents a vector in the plain, it makes sense to be able to do <code>Vec2D (2,3) * 4 == Vec2D (8,12)</code>.</li> </ul><br /><h3>回答1:</h3><br /><p>Very similar examples have been asked often already, and the answer is that this is <strong>not</strong> a number type and therefore should not have a <code>Num</code> instance. What it actually is is a vector space type, accordingly you should define instead</p> <pre><code>{-# LANGUAGE TypeFamilies #-} import Data.AdditiveGroup import Data.VectorSpace newtype T = T Int deriving Show instance AdditiveGroup T where T t1 ^+^ T t2 = T $ t1 + t2 zeroV = T 0 negateV (T t) = T $ -t instance VectorSpace T where type Scalar T = Int k *^ T t = T $ k * t </code></pre> <p>Then your <code>T -&gt; Int -&gt; T</code> operator is ^*, which is simply <code>flip (*^)</code>.</p> <p>That leads also to the more general what you should do when overloading a standard operator with a different meaning: just make it a <em>separate</em> definition. You don't even need to give it a different name, this can also be disambiguated using <code>qualified</code> module imports.</p> <p>Just please don't instantiate classes incompletely, in particular not <code>Num</code>. This just leads to php-ish confusion when somebody uses a generic function with those types, it compiles just fine but then horribly breaks at runtime when the calling code expects <code>Num</code> semantics but the type fails to actually offer that.</p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/65641353/what-is-the-correct-way-to-define-an-already-existing-e-g-in-prelude-operator</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/haskell" hreflang="zh-hans">haskell</a></div> <div class="field--item"><a href="/tag/functional-programming" hreflang="zh-hans">functional-programming</a></div> <div class="field--item"><a href="/tag/operator-overloading" hreflang="zh-hans">operator-overloading</a></div> <div class="field--item"><a href="/tag/typeclass" hreflang="zh-hans">typeclass</a></div> <div class="field--item"><a href="/tag/primitive-types" hreflang="zh-hans">primitive-types</a></div> </div> </div> Tue, 09 Feb 2021 01:22:49 +0000 我与影子孤独终老i 4083099 at https://www.e-learn.cn What is the correct way to define an already existing (e.g. in Prelude) operator between a user-defined type and an existing type? https://www.e-learn.cn/topic/4083063 <span>What is the correct way to define an already existing (e.g. in Prelude) operator between a user-defined type and an existing type?</span> <span><span lang="" about="/user/27" typeof="schema:Person" property="schema:name" datatype="">我只是一个虾纸丫</span></span> <span>2021-02-09 09:20:23</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>Suppose I have a custom type wrapping an existing type,</p> <pre class="lang-hs prettyprint-override"><code>newtype T = T Int deriving Show </code></pre> <p>and suppose I want to be able to add up <code>T</code>s, and that adding them up should result in adding the wrapped values up; I would do this via</p> <pre class="lang-hs prettyprint-override"><code>instance Num T where (T t1) + (T t2) = T (t1 + t2) -- all other Num's methods = undefined </code></pre> <p>I think we are good so far. Please, tell me if there are major concerns up to this point.</p> <p>Now let's suppose that I want to be able to multiply a <code>T</code> by an <code>Int</code> and that the result should be a <code>T</code> whose wrapping value is the former multiplied by the int; I would go for something like this:</p> <pre class="lang-hs prettyprint-override"><code>instance Num T where (T t1) + (T t2) = T (t1 + t2) (T t) * k = T (t * k) -- all other Num's methods = undefined </code></pre> <p>which obviously doesn't work because <code>class Num</code> declares <code>(*) :: a -&gt; a -&gt; a</code>, thus requiring the two operands (and the result) to be all of the same type.</p> <p>Even defining <code>(*)</code> as a free function poses a similar problem (i.e. <code>(*)</code> exists already in <code>Prelude</code>).</p> <p>How could I deal with this?</p> <p>As for the why of this question, I can device the following</p> <ul><li>in my program I want to use <code>(Int,Int)</code> for 2D vectors in a cartesian plane,</li> <li>but I also use <code>(Int,Int)</code> for another unrelated thing,</li> <li>therefore I have to disambiguate between the two, by using a <code>newtype</code> for at least one of them or, if use <code>(Int,Int)</code> for several other reasons, then why not making all of them <code>newtype</code>s wrapping <code>(Int,Int)</code>?</li> <li>since <code>newtype Vec2D = Vec2D (Int,Int)</code> represents a vector in the plain, it makes sense to be able to do <code>Vec2D (2,3) * 4 == Vec2D (8,12)</code>.</li> </ul><br /><h3>回答1:</h3><br /><p>Very similar examples have been asked often already, and the answer is that this is <strong>not</strong> a number type and therefore should not have a <code>Num</code> instance. What it actually is is a vector space type, accordingly you should define instead</p> <pre><code>{-# LANGUAGE TypeFamilies #-} import Data.AdditiveGroup import Data.VectorSpace newtype T = T Int deriving Show instance AdditiveGroup T where T t1 ^+^ T t2 = T $ t1 + t2 zeroV = T 0 negateV (T t) = T $ -t instance VectorSpace T where type Scalar T = Int k *^ T t = T $ k * t </code></pre> <p>Then your <code>T -&gt; Int -&gt; T</code> operator is ^*, which is simply <code>flip (*^)</code>.</p> <p>That leads also to the more general what you should do when overloading a standard operator with a different meaning: just make it a <em>separate</em> definition. You don't even need to give it a different name, this can also be disambiguated using <code>qualified</code> module imports.</p> <p>Just please don't instantiate classes incompletely, in particular not <code>Num</code>. This just leads to php-ish confusion when somebody uses a generic function with those types, it compiles just fine but then horribly breaks at runtime when the calling code expects <code>Num</code> semantics but the type fails to actually offer that.</p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/65641353/what-is-the-correct-way-to-define-an-already-existing-e-g-in-prelude-operator</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/haskell" hreflang="zh-hans">haskell</a></div> <div class="field--item"><a href="/tag/functional-programming" hreflang="zh-hans">functional-programming</a></div> <div class="field--item"><a href="/tag/operator-overloading" hreflang="zh-hans">operator-overloading</a></div> <div class="field--item"><a href="/tag/typeclass" hreflang="zh-hans">typeclass</a></div> <div class="field--item"><a href="/tag/primitive-types" hreflang="zh-hans">primitive-types</a></div> </div> </div> Tue, 09 Feb 2021 01:20:23 +0000 我只是一个虾纸丫 4083063 at https://www.e-learn.cn What is the correct way to define an already existing (e.g. in Prelude) operator between a user-defined type and an existing type? https://www.e-learn.cn/topic/4083032 <span>What is the correct way to define an already existing (e.g. in Prelude) operator between a user-defined type and an existing type?</span> <span><span lang="" about="/user/235" typeof="schema:Person" property="schema:name" datatype="">你。</span></span> <span>2021-02-09 09:16:15</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>Suppose I have a custom type wrapping an existing type,</p> <pre class="lang-hs prettyprint-override"><code>newtype T = T Int deriving Show </code></pre> <p>and suppose I want to be able to add up <code>T</code>s, and that adding them up should result in adding the wrapped values up; I would do this via</p> <pre class="lang-hs prettyprint-override"><code>instance Num T where (T t1) + (T t2) = T (t1 + t2) -- all other Num's methods = undefined </code></pre> <p>I think we are good so far. Please, tell me if there are major concerns up to this point.</p> <p>Now let's suppose that I want to be able to multiply a <code>T</code> by an <code>Int</code> and that the result should be a <code>T</code> whose wrapping value is the former multiplied by the int; I would go for something like this:</p> <pre class="lang-hs prettyprint-override"><code>instance Num T where (T t1) + (T t2) = T (t1 + t2) (T t) * k = T (t * k) -- all other Num's methods = undefined </code></pre> <p>which obviously doesn't work because <code>class Num</code> declares <code>(*) :: a -&gt; a -&gt; a</code>, thus requiring the two operands (and the result) to be all of the same type.</p> <p>Even defining <code>(*)</code> as a free function poses a similar problem (i.e. <code>(*)</code> exists already in <code>Prelude</code>).</p> <p>How could I deal with this?</p> <p>As for the why of this question, I can device the following</p> <ul><li>in my program I want to use <code>(Int,Int)</code> for 2D vectors in a cartesian plane,</li> <li>but I also use <code>(Int,Int)</code> for another unrelated thing,</li> <li>therefore I have to disambiguate between the two, by using a <code>newtype</code> for at least one of them or, if use <code>(Int,Int)</code> for several other reasons, then why not making all of them <code>newtype</code>s wrapping <code>(Int,Int)</code>?</li> <li>since <code>newtype Vec2D = Vec2D (Int,Int)</code> represents a vector in the plain, it makes sense to be able to do <code>Vec2D (2,3) * 4 == Vec2D (8,12)</code>.</li> </ul><br /><h3>回答1:</h3><br /><p>Very similar examples have been asked often already, and the answer is that this is <strong>not</strong> a number type and therefore should not have a <code>Num</code> instance. What it actually is is a vector space type, accordingly you should define instead</p> <pre><code>{-# LANGUAGE TypeFamilies #-} import Data.AdditiveGroup import Data.VectorSpace newtype T = T Int deriving Show instance AdditiveGroup T where T t1 ^+^ T t2 = T $ t1 + t2 zeroV = T 0 negateV (T t) = T $ -t instance VectorSpace T where type Scalar T = Int k *^ T t = T $ k * t </code></pre> <p>Then your <code>T -&gt; Int -&gt; T</code> operator is ^*, which is simply <code>flip (*^)</code>.</p> <p>That leads also to the more general what you should do when overloading a standard operator with a different meaning: just make it a <em>separate</em> definition. You don't even need to give it a different name, this can also be disambiguated using <code>qualified</code> module imports.</p> <p>Just please don't instantiate classes incompletely, in particular not <code>Num</code>. This just leads to php-ish confusion when somebody uses a generic function with those types, it compiles just fine but then horribly breaks at runtime when the calling code expects <code>Num</code> semantics but the type fails to actually offer that.</p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/65641353/what-is-the-correct-way-to-define-an-already-existing-e-g-in-prelude-operator</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/haskell" hreflang="zh-hans">haskell</a></div> <div class="field--item"><a href="/tag/functional-programming" hreflang="zh-hans">functional-programming</a></div> <div class="field--item"><a href="/tag/operator-overloading" hreflang="zh-hans">operator-overloading</a></div> <div class="field--item"><a href="/tag/typeclass" hreflang="zh-hans">typeclass</a></div> <div class="field--item"><a href="/tag/primitive-types" hreflang="zh-hans">primitive-types</a></div> </div> </div> Tue, 09 Feb 2021 01:16:15 +0000 你。 4083032 at https://www.e-learn.cn Why does this instance fail the coverage condition? https://www.e-learn.cn/topic/4082103 <span>Why does this instance fail the coverage condition?</span> <span><span lang="" about="/user/35" typeof="schema:Person" property="schema:name" datatype="">99封情书</span></span> <span>2021-02-08 23:45:00</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>Why does the following instance declaration fail the coverage condition in the absence of <code>UndecidableInstances</code>? It seems that if the functional dependency is satisfied in the context then it is satisfied in the new instance.</p> <pre><code>{-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE UndecidableInstances #-} class Foo a b | a -&gt; b where instance (Foo a b, Foo a' b') =&gt; Foo (a, a') (b, b') where </code></pre> <p>If I try to replicate the same thing with a type family there is no problem.</p> <pre><code>{-# LANGUAGE TypeFamilies #-} type family Bar a type instance Bar (a, b) = (Bar a, Bar b) </code></pre> <br /><h3>回答1:</h3><br /><p>I believe it's that constraints on instances aren't actually taken into account when selecting an instance. They become additional constraints to be proved at each use site, rather than limiting the applicability of the instance.</p> <p>So your instance declaration is kind of equivalent to <code>instance Foo (a, b) (c, d)</code>, which rather obviously fails the coverage condition.</p> <p>Adding the <code>(Foo a b, Foo a' b')</code> only makes it so that some of the <em>uses</em> of the instance would result in "no such instance" errors, it doesn't actually change the types for which your instance will be selected.</p> <br /><br /><br /><h3>回答2:</h3><br /><p>From the GHC docs:</p> <blockquote> <p>The Coverage Condition. For each functional dependency, tvsleft -&gt; tvsright, of the class, every type variable in S(tvsright) must appear in S(tvsleft), where S is the substitution mapping each type variable in the class declaration to the corresponding type in the instance declaration.</p> </blockquote> <p>In your class you have <code>a -&gt; b</code>, so <code>tvsleft = a</code> and <code>tvsright = b</code>. The substitution <code>S</code> maps <code>a</code> into <code>S(a)=(a,a')</code> and <code>b</code> into <code>S(b)=(b,b')</code>.</p> <p>So, we find type variables in <code>S(tvsright)=S(b)=(b,b')</code> (both <code>b</code> and <code>b'</code>) which do not appear in <code>S(tvsleft)=S(a)=(a,a')</code>. Hence the coverage condition fails.</p> <p>As @Ben said, the coverage condition does not take the context into account: only the instance head matters.</p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/26275940/why-does-this-instance-fail-the-coverage-condition</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/haskell" hreflang="zh-hans">haskell</a></div> <div class="field--item"><a href="/tag/typeclass" hreflang="zh-hans">typeclass</a></div> <div class="field--item"><a href="/tag/functional-dependencies" hreflang="zh-hans">functional-dependencies</a></div> </div> </div> Mon, 08 Feb 2021 15:45:00 +0000 99封情书 4082103 at https://www.e-learn.cn typeclasses without methods, used as constraints: do they get dictionaries? https://www.e-learn.cn/topic/4081836 <span>typeclasses without methods, used as constraints: do they get dictionaries?</span> <span><span lang="" about="/user/34" typeof="schema:Person" property="schema:name" datatype="">爱⌒轻易说出口</span></span> <span>2021-02-08 20:50:14</span> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><h3>问题</h3><br /><p>If I'm using a typeclass to overload methods, that's implemented in 'dictionary passing style'. That is, the method gets an extra argument (that doesn't appear in surface Haskell); to resolve overloading the method looks up the dictionary by type of its 'proper' argument(s); and pulls a method implementation out of the dictionary. As described in this q, for example.</p> <p>But what about typeclasses without methods? They can be used as constraints. Is there a dictionary for them? What does it contain?</p> <p>For a specific example:</p> <pre><code>module M where class C a -- no methods -- no instances in module M f :: C a =&gt; a -&gt; Bool f x = blah </code></pre> <p>There's no instances for <code>C</code> in this module, so if <code>M</code> gets imported into some other module (with <code>C</code> instances) how is <code>f</code>'s dictionary lookup encoded?</p> <p>The usual situation would be that class <code>C</code> has method(s); there's calls to them on RHS of the equation for <code>f</code>; so the wanted <code>C a</code> is encoded as a dictionary lookup for the method call.</p> <p><strong>Supplementary q's:</strong> (if anybody's still listening)</p> <p>2a. For no-method typeclasses with superclass constraints: Where do the constraints go in the dictionary? A comment on a ticket from SPJ seems to suggest it's an argument to the dictionary's data constructor.</p> <p>2b. For no-method typeclass instances with constraints: Again where do the constraints go in the dictionary?</p> <p><strong>Motivation</strong></p> <p>@Daniel in the comments is asking the motivation for these q's. Apart from just understanding compiler internals a bit better ...</p> <p>GHC translates surface Haskell into an Internal Representation: System F<sub>C</sub>, which has aot explicit type signatures at every function application. (Those applications must include applying to the dictionaries for a class.) I'm trying to understand where all the type-related components of class and instance decls go inside the dictionaries; to figure out how a term in F<sub>C</sub> gets to an equivalent representation to the original Haskell. Then I don't understand how [typeclasses without methods] fit in. Because those classes cannot appear directly as terms in surface Haskell, but only as constraints. Then it must be dictionar(ies) for such a class that represent it at term level.</p> <p>If you want to ask where this is going: there seems to be a limitation in F<sub>C</sub> that it can't represent Functional Dependencies. Something to do with being unable to generate type-level evidence. Then I want to understand how that limitation arises/what about FunDeps can't be (or currently isn't) represented?</p> <br /><h3>回答1:</h3><br /><blockquote> <p>Is there a dictionary for [typeclasses without methods]? What does it contain?</p> </blockquote> <p>Yes, there is a dictionary with no fields.</p> <p>Compare:</p> <pre><code>class Monoid a where mempty :: a mappend :: a -&gt; a -&gt; a data DictMonoid a = DictMonoid a (a -&gt; a -&gt; a) class C a data DictC a = DictC </code></pre> <blockquote> <p>If <code>M</code> gets imported into some other module (with <code>C</code> instances) how is <code>f</code>'s dictionary lookup encoded?</p> </blockquote> <p>Type inference is used to determine what instance is needed when <code>f</code> is called; then GHC looks up that type in its collection of known instances (=known dictionaries).</p> <p>One possible outcome of this process is that the instance we determine would be needed is polymorphic, and there is no fully polymorphic instance. Then the appropriate constraint (such as <code>C a</code> or <code>C m</code> or whatever) is attached to the inferred type of whatever term is calling <code>f</code> -- which is then compiled to a function which accepts a dictionary on <code>f</code>'s behalf and passes it on.</p> <blockquote> <p>For no-method typeclasses with superclass constraints: Where do the constraints go in the dictionary?</p> </blockquote> <p>Somewhere. There's no observation you can make from the surface language to distinguish between different places. For example, consider:</p> <pre><code>class Semigroup a =&gt; Monoid a where mempty :: a data DictMonoid1 a = DictMonoid1 (DictSemigroup a) a data DictMonoid2 a = DictMonoid2 a (DictSemigroup a) </code></pre> <p>These are sort of the only two choices one could make for where to put the superclass' dictionary. But what difference could it possibly make?</p> <p>Okay, but you asked about no-method typeclasses. But the answer is the same. You can't tell the order that superclass dictionaries are stored in.</p> <pre><code>class (A a, B a) =&gt; C a data DictC1 a = DictC1 (DictA a) (DictB a) data DictC2 a = DictC2 (DictB a) (DictA a) </code></pre> <p>What could you possibly do to tell the difference between these? Nothing.</p> <blockquote> <p>For no-method typeclass instances with constraints: Again where do the constraints go in the dictionary?</p> </blockquote> <p>Nowhere. They become arguments that the caller must supply to receive a dictionary. Particular fields of the supplied dictionary may be closed over by the new dictionary, of course. Example:</p> <pre><code>class Ord a where compare :: a -&gt; a -&gt; Ordering data DictOrd a where DictOrd (a -&gt; a -&gt; Ordering) instance (Ord a, Ord b) =&gt; Ord (a, b) where compare (a,b) (a',b') = compare a a' &lt;&gt; compare b b' instanceOrdTuple :: DictOrd a -&gt; DictOrd b -&gt; DictOrd (a,b) instanceOrdTuple (DictOrd comparea) (DictOrd compareb) = DictOrd $ \(a,b) (a',b') -&gt; comparea a a' &lt;&gt; compareb b b' </code></pre> <p>Okay, but you asked about no-method typeclasses. But the answer is not significantly different. The instance's constraint dictionaries are not stored anywhere, just like before; the only difference is that now we can also be sure that even the fields of the supplied dictionaries are not closed over.</p> <pre><code>class A a where whateverA :: a -&gt; Int class B a where whateverB :: Int -&gt; a class C a data DictA a = DictA (a -&gt; Int) data DictB a = DictB (Int -&gt; a) data DictC a = DictC instance (A a, B a) =&gt; C [a] instanceCList :: DictA a -&gt; DictB a -&gt; DictC [a] instanceCList (DictA whateverAa) (DictB whateverBa) = DictC </code></pre> <p><strong>The following commentary replies to an old version of the question.</strong></p> <blockquote> <p>There's no instances for <code>C</code> in this module, so the compiler can't discharge <code>f</code>s constraint.</p> </blockquote> <p>It doesn't need to. <code>f</code> is compiled to a function which <em>takes</em> a dictionary as an argument; there's no need to create a dictionary to compile <code>f</code>, only to compile its callers.</p> <blockquote> <p>The compiler can't discharge the <code>C Char</code> constraint arising from the equation for <code>y</code>. What does it do?</p> </blockquote> <p>It reports that it can't discharge the <code>C Char</code> constraint and exits unsuccessfully. (This hardly even qualifies as a question -- just try it and see for yourself!)</p> <br /><br /><p>来源:<code>https://stackoverflow.com/questions/55358056/typeclasses-without-methods-used-as-constraints-do-they-get-dictionaries</code></p></div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field--label">标签</div> <div class="field--items"> <div class="field--item"><a href="/tag/haskell" hreflang="zh-hans">haskell</a></div> <div class="field--item"><a href="/tag/typeclass" hreflang="zh-hans">typeclass</a></div> </div> </div> Mon, 08 Feb 2021 12:50:14 +0000 爱⌒轻易说出口 4081836 at https://www.e-learn.cn