LoginSignup
5
2

More than 5 years have passed since last update.

Recursion schemeとHaskell

Posted at

Recursion schemeという、foldr、unfoldrを一般化した概念があるらしいのでHaskellで色々実装してみた。あとchronomorphismのかっこよさは異常(←しつこい)。

{-# LANGUAGE StandaloneDeriving, UndecidableInstances #-}

import Control.Monad
import Control.Monad.Free
import Control.Comonad
import Control.Comonad.Cofree

newtype Fix f = Fix (f (Fix f))

unfix (Fix f) = f

deriving instance Show (f (Fix f)) => Show (Fix f)

-- morphisms

hylo :: Functor f => (f b -> b) -> (a -> f a) -> a -> b
hylo f g = f . fmap (hylo f g) . g

cata :: Functor f => (f a -> a) -> Fix f -> a
cata f = hylo f unfix

ana :: Functor f => (a -> f a) -> a -> Fix f
ana f = hylo Fix f

histo :: Functor f => (f (Cofree f a) -> a) -> Fix f -> a
histo f = extract . cata (\x -> f x :< x)

futu :: Functor f => (a -> f (Free f a)) -> a -> Fix f
futu f = ana g . return where
    g (Pure a) = f a
    g (Free fm) = fm

chrono :: Functor f => (f (Cofree f b) -> b) -> (a -> f (Free f a)) -> a -> b
chrono f g = histo f . futu g

-- list from Fix

data ListF e a = Empty | Cons e a deriving Show

instance Functor (ListF e) where
    fmap _ Empty = Empty
    fmap f (Cons e a) = Cons e (f a)

listF :: b -> (e -> a -> b) -> ListF e a -> b
listF a _ Empty = a
listF _ f (Cons e a) = f e a

type List e = Fix (ListF e)

fromList :: [a] -> List a
fromList = ana (uncons Empty Cons) where

toList :: List a -> [a]
toList = cata (listF [] (:))

unfoldr_ :: (b -> Maybe (a, b)) -> b -> List a
unfoldr_ f = ana $ maybe Empty (uncurry Cons) . f

foldr_ :: (a -> b -> b) -> b -> List a -> b
foldr_ = (cata.) . flip listF

uncons :: b -> (a -> [a] -> b) -> [a] -> b
uncons e _ [] = e
uncons _ f (x:xs) = f x xs
5
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
2