Skip to content

Composability and/or associativity for scaling #51

@smilack

Description

@smilack

Composability

Potentially a Semigroupoid instance:

Semigroupoid

class Semigroupoid a where

A Semigroupoid is similar to a Category but does not require an identity element identity, just composable morphisms.

Semigroupoids must satisfy the following law:

  • Associativity: p <<< (q <<< r) = (p <<< q) <<< r

One example of a Semigroupoid is the function type constructor (->), with (<<<) defined as function composition.

Members

  • compose :: forall d c b. a c d -> a b c -> a b d

If it will be possible to create arbitrary Scalers (#50), then chaining them may become a problem. Consider an application containing a certain area that should be treated as a cartesian graph:

  • canvasdrawing
  • drawinggraph

Going between canvas and graph requires two conversions:

(graphCoords *~> drawing) *~> canvas

I believe that the scaling functions should be composable, so that this would be equivalent:

graphToCanvas = drawing >>> canvas
graphCoords *~> graphToCanvas

Problem

A Semigroupoid instance would require Scaler to have a newtype or data definition, and type parameters for the from and to types. Something like:

import Gesso.Geometry (Scaler, Canvas, Drawing, mkScaler)

data Graph

graphToDrawing :: Scaler Graph Drawing 
graphToDrawing = _.b $ mkScaler graphRect drawing.rect

-- assuming `scalers` is in context
graphToCanvas :: Scaler Graph Canvas
graphToCanvas = graphToDrawing >>> scalers.canvas

But the convenience fields would become less convenient, e.g.:

graphRect = getX drawingToGraph
-- or:
_.x $ unwrap $ drawingToGraph

Alternative

Composition doesn't necessarily require Semigroupoid. Nothing prevents this:

compose :: Scaler -> Scaler -> Scaler
compose aToB bToC = bToC
  { scaling
      { all = aToB.all >>> bToC.all
      , x = aToB.x >>> bToC.x
      , y = aToB.y >>> bToC.y
      , length = aToB.length >>> bToC.length
      }
  }

Associativity

Alternately, or in addition, the scaling operators could be changed from infix to infixr or infixl.

(graphCoords *~> drawing) *~> canvas -- fine
graphCoords *~> (drawing *~> canvas) -- not fine

canvas <~* (drawing <~* graphCoords) -- fine
(canvas <~* drawing) <~* graphCoords -- not fine

canvas <~* graphCoords *~> drawing -- definitely not fine

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestscalingAnything involving coordinate transformation

Projects

Status

Idea

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions