Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
fomo sacer
Feb 14, 2007

The March Hare posted:

Does anyone have a good resource for gaining an understanding of category theory for code bros who know almost nothing about math? It's OK if this isn't a thing, but if it is I'd appreciate a recommendation for a decent resource.

I like Categories For Scientists (edit: here is the current edition of the book from the publisher's website as ugly HTML instead of an ugly pdf) as a gentle/somewhat practical survey of category theory. It may end up being more math-y than you're looking for but it's also free on the internet, so worth taking a peek at.

fomo sacer fucked around with this message at 00:46 on Nov 19, 2016

Adbot
ADBOT LOVES YOU

fomo sacer
Feb 14, 2007

loose-fish posted:

While playing around with generic execution models I ran into the following, a typeclass with a function that returns another instance of that typeclass:
code:
class Processor a where
    process :: Processor b => a -> Int -> b

data P = P Int

instance Processor P where
    process (P x) y = P y
-- can't return P because it's no Processor

-- more precise, but pointless
instance (Processor P) => Processor P where
    process (P x) y = P y
Is there a way to achieve something like this in Haskell? Type families maybe? I'm not up to speed on all extensions...

The way you've written Processor is requiring that a Processor can be turned into any other instance of Processor by calling process on it, i.e. the return type of process needs to be polymorphic, but when you wrote the instance for P, you fixed the return type as P.

You can fix this by requiring Processors to provide you with a generic constructor function:
code:
class Processor a where
  fromInt :: Int -> a
  process :: Processor b => a -> Int -> b
  
data P = P Int

instance Processor P where
  fromInt = P
  process (P a) b = fromInt b
Alternatively, you can use multi-parameter type classes to represent the idea that one type can be processed into another type:
code:
{-# Language MultiParamTypeClasses #-} 
class Processor a b where
  process :: a -> Int -> b
  
data P = P Int
data Q = Q Int

instance Processor P Q where
  process (P a) b = Q (a*b)

instance Processor Q P where
  process (Q a) b = P (a+b)
In this case, GHC may have trouble with type inference unless you sprinkle type annotations all over your code. You can avoid this with functional dependencies, at the cost of some flexibility:
code:
{-# Language MultiParamTypeClasses #-}
{-# Language FunctionalDependencies #-} 
class Processor a b | a -> b where -- a determines b. b -> a is also possible
  process :: a -> Int -> b
  
data P = P Int
data Q = Q Int

instance Processor P Q where
  process (P a) b = Q (a*b)

instance Processor Q P where
  process (Q a) b = P (a+b)

instance Processor P P where -- not allowed, we already have an instance of Processor P _
  process = undefined

fomo sacer fucked around with this message at 00:57 on May 21, 2017

  • Locked thread