Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this weaker semialign a known abstraction?

I have a class which looks a lot like SemiAlign, but isn't:

class
  ( Functor f
  )
    => Weakalign f
  where
    {-# Minimal alignLeft | alignRight #-}
    alignLeft :: f a -> f b -> f (Either a b)
    alignLeft =
      (fmap swap .) . flip alignRight
    alignRight :: f a -> f b -> f (Either a b)
    alignRight =
      (fmap swap .) . flip alignLeft

swap :: Either a b -> Either b a
swap (Left x) =
  Right x
swap (Right x) =
  Left x

alignLeft aligns two structures always taking the left value on conflict, and alignRight does the same but preferring the right value.

Both can be defined in terms of alignWith or align:

alignLeft ::
  ( Semialign f
  )
    => f a -> f b -> f (Either a b)
alignLeft =
  alignWith go
  where
    go (This x) =
      Left x
    go (That y) =
      Right y
    go (These x _) =
      Left x

But neither align nor alignWith can be defined in terms of alignLeft or alignRight. As a demonstration of why consider the following instance:

instance Weakalign ((,) a) where
  alignLeft =
    const

Thanks to Daniel Wagner for simplifying this example.

This is a perfectly valid Weakalign instance, but it cannot be extended to a law abiding Semialign.

That is a bit of a trivial example though. You might consider instead a parser type:

data Parser a b
  = Parser (a -> [(a, b)])

We could define alignLeft as a fall through operation, which tries the first parser and only if it fails tries the second parser. For the same reason as the tuple there would be no way to extend the parser to a full SemiAlign instance.

I checked the semialign package and it doesn't seem like this corresponds to any existing class there. However it seems like something that would already exist somewhere. And I'm wondering if maybe it exists in another align-like package I don't know of, or maybe I'm barking up the wrong tree and this isn't related to align.

Either way I'd prefer to use an extant library for this sort of thing instead of inventing my own.

Is this a known abstraction?

like image 299
Wheat Wizard Avatar asked Sep 17 '25 07:09

Wheat Wizard


1 Answers

Perhaps Alternative meets your needs. Something like alignLeft can be implemented this way:

alignLeft :: Alternative f => f a -> f b -> f (Either a b)
alignLeft fa fb = (Left <$> fa) <|> (Right <$> fb)

Similarly for alignRight, with the arguments to <|> simply swapped:

alignRight :: Alternative f => f a -> f b -> f (Either a b)
alignRight fa fb = (Right <$> fb) <|> (Left <$> fa)

It isn't exactly the class you specified. In particular there's not really a good (,) instance (but see also Alt). But it should meet your needs for Parser, and is a very commonly provided operation in existing parser combinator libraries.

like image 121
Daniel Wagner Avatar answered Sep 19 '25 21:09

Daniel Wagner