Last active
August 29, 2015 14:20
-
-
Save elbeno/a82f9eea521adc38235f to your computer and use it in GitHub Desktop.
Writer monad idea, with foldable things instead of monoids
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE MultiParamTypeClasses #-} | |
{-# LANGUAGE FlexibleInstances #-} | |
{-# LANGUAGE FunctionalDependencies #-} | |
module Main where | |
-- Here's the familiar Writer monad. For the purposes here, we're not worried | |
-- about the instances for functor, monad etc. | |
newtype Writer a x = Writer { runWriter :: (x, a) } | |
-- Here's something like a relaxed monoid: an accumulator (a) that can have bs | |
-- added to it. If a and b are the same, this is a regular monoid of course. | |
class Foldoid a b | a->b where | |
fempty :: a | |
fappend :: a -> b -> a | |
-- Here's something like a relaxed monad: it has two type variables and a | |
-- function is allowed to change both. The idea is that if a and b have a | |
-- Foldoid instance, we can write fbind. | |
class Foldad m a b where | |
(>>>=) :: m a x -> (x -> m b y) -> m a y | |
freturn :: x -> m a x | |
-- >>>= gets the same precedence/fixity as >>= | |
infixl 1 >>>= | |
-- So here's Writer generalised with Foldoid instead of Monoid. | |
instance (Foldoid a b) => Foldad Writer a b where | |
(Writer (x, a)) >>>= f = let (Writer (y, b)) = f x | |
in Writer (y, a `fappend` b) | |
freturn x = Writer (x, fempty) | |
-- Here's a simple Foldoid that accumulates the max length of strings you feed | |
-- it. | |
instance Foldoid Int String where | |
fempty = 0 | |
fappend n s = max n (length s) | |
-- The first 10 natural numbers as words. | |
numbers :: [String] | |
numbers = [ "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"] | |
-- A regular writer that just stores the string of its number. | |
logNumberLength :: Int -> Writer String Int | |
logNumberLength x = Writer (x, numbers !! x) | |
-- Now we can log number lengths and remember the longest. | |
logLengths :: Writer Int Int | |
logLengths = | |
freturn (0 :: Int) >>>= | |
(\_ -> logNumberLength 3) >>>= -- "three" = length 5 | |
\_ -> logNumberLength 2 -- "two" = length 3 | |
main :: IO () | |
main = print $ runWriter logLengths | |
-- output: (2,5) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment