A2FP / a2fp

Ann Arbor Functional Programming User Group
11 stars 3 forks source link

Talk on semigroups #25

Closed gbwey closed 6 years ago

gbwey commented 6 years ago

Hi, I am interested in doing a talk about semigroups. It is aimed at a more introductory haskell level. The duration of the talk is about 45 minutes and I can do it anytime.

Semigroup is the quintessential haskell type class that provides a simple and yet useful way to combine values. I'll show, how to apply semigroups to solve practical problems and show the depth that this seemingly simple typeclass gives us. I will include examples using horizontal, vertical composition and more!

Best, Grant

BebeSparkelSparkel commented 6 years ago

I'll go to that!

filippovitale commented 6 years ago

Hi Grant, thanks for the proposal, I

We never had a presenter for two months in a row, I don't see a problem with that if everybody is happy with it. Which day would be OK for you if you would like to present this month?

BTW I made a presentation about semigroup using Scala as main language last October but that doesn't mean we shouldn't have this talk!

filippovitale commented 6 years ago

Horizontal and vertical composition: this talk sounds very good!

gbwey commented 6 years ago

Tuesday the 28th is perfect. I didnt realise you had given a presentation already but I am hoping this is a slightly different take on semigroups. Thanks so much for setting this up and it should be fun Best, Grant

filippovitale commented 6 years ago

Thank you very much Grant!

BebeSparkelSparkel commented 6 years ago

@gbwey

Hey Grant,

Your semigroup talk got me thinking today and it seems like there’s a lot of places where it can be applied in my project.

My trouble is having the semigroup code be more clear than the manual piecing together of the operations.

-- how it is now
instance Arbitrary Ratio where
  arbitrary = do
    num <- arbitrary
    den <- suchThat arbitrary (\x -> x /= 0 && abs num < abs x)
    return $ Ratio (num / den)

-- seemingly bad semigroup solution
instance Arbitrary Ratio where
  arbitrary = do
    num <- arbitrary
    den <- suchThat arbitrary (getAll . (All . (/= 0) <> All . ((> abs num) . abs)))
    return $ Ratio (num / den)

-- from list
instance Arbitrary Ratio where
  arbitrary = do
    num <- arbitrary
    den <- suchThat arbitrary (sgfm All getAll [(/= 0), (> abs num) . abs])
    return $ Ratio (num / den)

-- more readable
instance Arbitrary Ratio where
  arbitrary = do
    num <- arbitrary
    let absOfNumLTDen = (> abs num) . abs
    den <- suchThat arbitrary (mustPass [(/= 0), absOfNumLTDen])
    return $ Ratio (num / den)

-- combines the functions
sgfm :: Semigroup g => (b -> g) -> (g -> b) -> [a -> b] -> a -> b
sgfm to from (f0:fs) = from . foldr (\f sg -> sg <> to . f) (to . f0) fs

mustPass = sgfm All getAll

Are any of these actually better than the origional?
It seems like the conditions are more easily extendable.
Do you have any better ideas?

One last question, how would you quickcheck the sgfm function?

mwotton commented 6 years ago

@gbwey could you put up your slides? some external people interested too.

filippovitale commented 6 years ago

Hi @mwotton, slides are up: https://github.com/A2FP/a2fp/tree/master/slides/2018-08-28%20meetup

/cc @BebeSparkelSparkel

gbwey commented 6 years ago

Hi @BebeSparkelSparkel Sorry, I didn't check the messages in a while. Here are a couple of ways you could fold over a list of predicates.

z0 uses traversable and no semigroups but is concise z1 uses monoids and ala from Lens to automatically wrap and unwrap z2 uses monoids and does a coerce so depends on type inference or a signature

-- semigroup version of sgfm sgfm' :: Semigroup g => (b -> g) -> (g -> b) -> [a -> b] -> (a -> b) sgfm' to from (f0:fs) = from . SF.foldMap1 to . ST.sequence1 (f0 :| fs)

import Data.Coerce import Control.Lens import Control.Arrow import Data.Semigroup import Data.List.NonEmpty import qualified Data.Semigroup.Foldable as SF import qualified Data.Semigroup.Traversable as ST

z0 = and . sequence [(/=0),(>3)] z1 = ala All foldMap . (sequence [(/=0),(>3)])

z2 :: Int -> Bool z2 = coerce . foldMap All . (sequence [(/=0),(>3)])

sgfm :: Semigroup g => (b -> g) -> (g -> b) -> [a -> b] -> a -> b sgfm to from (f0:fs) = from . foldr (\f sg -> sg <> to . f) (to . f0) fs