problem-specifications icon indicating copy to clipboard operation
problem-specifications copied to clipboard

Exercise Idea: composite-resistors

Open sshine opened this issue 5 years ago • 11 comments

This exercise is proposed in the context of the Haskell track, but I'm posting it here because I like the idea of sharing exercise ideas across, and monoid abstractions exist in other languages, too. In the process of porting resistor-color-trio in exercism/haskell#869, it occurred to me that resistors are monoids in two ways:

When you put them in series, they form an additive monoid (resistance adds up) with (black, black, black), better known as a wire, as the identity resistor. And when you put them in parallel, you don't exactly get a multiplicative monoid, since n resistors in parallel add up like 1/R = 1/R₁ + 1/R₂ + ... + 1/Rₙ. What's the identity resistor for a parallel circuit?

It isn't a wire, since then the current would follow the path of least resistance, which would always end up being the wire. A neutral resistor in a parallel circuit is any non-conductive material with infinite resistance. For example, my willingness to code in another language than Haskell.

Putting resistors in series and in parallel is neat in practice for making non-standard resistors or when you run out of a certain kind of resistor.

Haskell has some machinery for dealing with types that are monoids in more than one way: while one can define instance Monoid (Sum Resistor) where ... for the built-in Sum type, it seems necessary to define one's own Parallel type and make instance Monoid (Parallel Resistor) where ... instead.

Having this exercise in succession of resistor-color-trio leads to interesting thoughts:

  • The data type Resistor is given as a newtype wrapper around (Color, Color, Color).
  • But that means there is no constructor for a resistor with infinite resistance.
  • But that means some composite resistors don't have such a representation:
    let   r50 = Resistor (Green, Black, Black)
        r1000 = Resistor (Brown, Black, Orange)
        r1050 = getSum (Sum r50 <> Sum r1000)
    
    r1050 == Resistor (???)
    
  • But that's okay, because this representation has another bad property:
    let ten1 = Resistor (Brown, Black, Black)
        ten2 = Resistor (Black, Brown, Brown)
    
    ohms ten1 == ohms ten2 -- True
    ten1      == ten2      -- False
    
    (We don't compare Resistors for equality in -trio, so we live with it there.)
  • A necessary part of this exercise would then be to refactor the representation of -trio.
  • This is an excellent opportunity for property-based tests of monoidal laws.

sshine avatar Oct 14 '19 11:10 sshine