adavydow
adavydow

Reputation: 41

Protocol inheritance

Sometimes it is convenient to have an inheritance structure on interfaces: For example:

But every applicative functor is a functor: (def fmap #(fapply (pure %1) %2)).

The first solution I came to is the following:

However this solutions smells as it looks like cheating a clojure type system.

The second solution is to define a macro extend-applicative which will automatically implement Functor protocol. But this solution do not look great also as it requires additional work from user of the library and it allows sepparate definition of functor/applicative instances which can easily lead to an error.

Is there a better way to express this kind of relations in clojure?

Upvotes: 4

Views: 1221

Answers (1)

Magos
Magos

Reputation: 3014

EDIT: As Thumbnail says, this turned out to be a faulty approach - I was only testing records implementing the protocol interface and didn't notice that extending the Applicative protocol didn't actually implement Functor.

Remember, extend does not require that the type being extended is a concrete implementation; one protocol can extend anotheryou can extend interfaces and abstract classes, too. You should be able to do something like

Applicative.clj

(ns protocol.applicative)
(defprotocol Applicative
      (fapply [f g])
      (pure [x] ))

functor.clj

(ns protocol.functor
  (:import [protocol.applicative.Applicative])
  (:require [protocol.applicative :refer [fapply pure]])
  )

(defprotocol Functor
  (fmap [this f]))

(extend-protocol Functor
  protocol.applicative.Applicative
    (fmap [this f] (fapply (pure f) this)))

Multiple files and importing is my attempt to deal with some compilation order issues which come up; you'll also have to add the two to AOT. Hope that helps you get it working.

Upvotes: 3

Related Questions