Writing cojoin or cobind for n-dimensional grid type

前端 未结 3 596
清歌不尽
清歌不尽 2020-12-22 22:53

Using the typical definition of type-level naturals, I\'ve defined an n-dimensional grid.

{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANG         


        
3条回答
  •  情话喂你
    2020-12-22 23:41

    So this turns out to be wrong. I'll leave it here in case anybody wants to try to fix it.

    This implementation is the way @pigworker suggested I think. It compiles, but I haven't tested it. (I took the cojoin1 implementation from http://blog.sigfpe.com/2006/12/evaluating-cellular-automata-is.html)

    {-# LANGUAGE KindSignatures #-}
    {-# LANGUAGE DataKinds #-}
    {-# LANGUAGE GADTs #-}
    {-# LANGUAGE TypeFamilies #-}
    
    data Nat = Z | S Nat
    
    data U (n :: Nat) x where
      Point :: x -> U Z x
      Dimension :: [U n x] -> U n x -> [U n x] -> U (S n) x
    
    unPoint :: U Z x -> x
    unPoint (Point x) = x
    
    dmap :: (U n x -> U m r) -> U (S n) x -> U (S m) r
    dmap f (Dimension ls mid rs) = Dimension (map f ls) (f mid) (map f rs)
    
    right, left :: U (S n) x -> U (S n) x
    right (Dimension a b (c:cs)) = Dimension (b:a) c cs
    left  (Dimension (a:as) b c) = Dimension as a (b:c)
    
    instance Functor (U n) where
      fmap f (Point x) = Point (f x)
      fmap f d@Dimension{} = dmap (fmap f) d
    
    class Functor w => Comonad w where
      (=>>)    :: w a -> (w a -> b) -> w b
      coreturn :: w a -> a
      cojoin   :: w a -> w (w a)
    
      x =>> f = fmap f (cojoin x)
      cojoin xx = xx =>> id
    
    instance Comonad (U n) where
      coreturn (Point x) = x
      coreturn (Dimension _ mid _) = coreturn mid
      cojoin (Point x) = Point (Point x)
      cojoin d@Dimension{} = fmap unlayer . unlayer . fmap dist . cojoin1 . fmap cojoin . layer $ d
    
    dist :: U (S Z) (U n x) -> U n (U (S Z) x)
    dist = layerUnder . unlayer
    
    layerUnder :: U (S n) x -> U n (U (S Z) x)
    layerUnder d@(Dimension _ Point{} _) = Point d
    layerUnder d@(Dimension _ Dimension{} _) = dmap layerUnder d
    
    unlayer :: U (S Z) (U n x) -> U (S n) x
    unlayer = dmap unPoint
    
    layer :: U (S n) x -> U (S Z) (U n x)
    layer = dmap Point
    
    cojoin1 :: U (S Z) x -> U (S Z) (U (S Z) x)
    cojoin1 a = layer $ Dimension (tail $ iterate left a) a (tail $ iterate right a)
    

提交回复
热议问题