n 차원 그리드 유형에 대한 cojoin 또는 cobind 작성
유형 수준 내추럴의 일반적인 정의를 사용하여 n 차원 그리드를 정의했습니다.
{-# 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
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)
instance Functor (U n) where
fmap f (Point x) = Point (f x)
fmap f d@Dimension{} = dmap (fmap f) d
이제 나는 그것을 Comonad의 인스턴스로 만들고 싶지만 내 뇌를 감싸지 못합니다.
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 :: U Z x -> U Z (U Z x)
cojoin (Point x) = Point (Point x)
-- cojoin ::U (S n) x -> U (S n) (U (S n) x)
cojoin d@Dimension{} = undefined
-- =>> :: U Z x -> (U Z x -> r) -> U Z r
p@Point{} =>> f = Point (f p)
-- =>> :: U (S n) x -> (U (S n) x -> r) -> U (S n) r
d@Dimension{} =>> f = undefined
cojoin
n 차원 그리드에서 사용 하면 n 차원 그리드의 n 차원 그리드가 생성됩니다. I는 동일한 아이디어 인스턴스를 제공하려는 이와 점이다 값 의 cojoined (X, Y, Z)에 그리드가 있어야 원래 격자 중심 (X, Y, Z)에. 이 코드를 수정하려면 "fmaps"및 "rolls" n
를 수행하기 위해 수정 해야하는 것으로 보입니다 . 그런 식으로 할 필요는 없지만 도움이된다면 거기로 갈 수 있습니다.n
n
Jagger / Richards : 항상 원하는 것을 얻을 수있는 것은 아니지만 가끔 시도하면 필요한 것을 얻을 수 있습니다.
목록의 커서
공간 속성을 명확하게 유지하기 위해 snoc 및 cons-list를 사용하여 구조의 구성 요소를 다시 작성하겠습니다. 나는 정의한다
data Bwd x = B0 | Bwd x :< x deriving (Functor, Foldable, Traversable, Show)
data Fwd x = F0 | x :> Fwd x deriving (Functor, Foldable, Traversable, Show)
infixl 5 :<
infixr 5 :>
data Cursor x = Cur (Bwd x) x (Fwd x) deriving (Functor, Foldable, Traversable, Show)
코 모나드를 갖자
class Functor f => Comonad f where
counit :: f x -> x
cojoin :: f x -> f (f x)
커서가 코 모나드인지 확인하겠습니다.
instance Comonad Cursor where
counit (Cur _ x _) = x
cojoin c = Cur (lefts c) c (rights c) where
lefts (Cur B0 _ _) = B0
lefts (Cur (xz :< x) y ys) = lefts c :< c where c = Cur xz x (y :> ys)
rights (Cur _ _ F0) = F0
rights (Cur xz x (y :> ys)) = c :> rights c where c = Cur (xz :< x) y ys
이런 종류의 물건을 켜면 Cursor
공간적으로 즐거운 변형임을 알 수 있습니다.InContext []
InContext f x = (x, ∂f x)
여기서 ∂는 펑터의 형식적 도함수를 취하여 원홀 컨텍스트의 개념을 제공합니다. 이 답변 에서 언급했듯이 InContext f
는 항상입니다. 여기서 우리가 가진 것은 차등 구조에 의해 유도 된 것입니다. 여기서 초점에있는 요소를 추출하고 각 요소를 자체 컨텍스트로 장식하여 효과적으로 초점을 다시 맞춘 커서로 가득 찬 컨텍스트를 제공합니다. 초점에 움직이지 않은 커서가 있습니다. 예를 들어 보겠습니다.Comonad
Comonad
counit
cojoin
> cojoin (Cur (B0 :< 1) 2 (3 :> 4 :> F0))
Cur (B0 :< Cur B0 1 (2 :> 3 :> 4 :> F0))
(Cur (B0 :< 1) 2 (3 :> 4 :> F0))
( Cur (B0 :< 1 :< 2) 3 (4 :> F0)
:> Cur (B0 :< 1 :< 2 :< 3) 4 F0
:> F0)
보다? 초점이 맞춰진 2는 커서가 2가되도록 장식되었습니다. 왼쪽에는 cursor-at-1의 목록이 있습니다. 오른쪽에는 커서 -at-3 및 커서 -at-4의 목록이 있습니다.
커서 작성, 커서 전치?
자, 당신이 요구하는 구조 Comonad
는 Cursor
. 가자
newtype (:.:) f g x = C {unC :: f (g x)} deriving Show
코 모나드를 설득 f
하고 g
작곡 하려면 counit
깔끔하게 작곡하지만 '분배 법'이 필요합니다.
transpose :: f (g x) -> g (f x)
그래서 당신은 합성 할 수있다 cojoin
이 같은를
f (g x)
-(fmap cojoin)->
f (g (g x))
-cojoin->
f (f (g (g x)))
-(fmap transpose)->
f (g (f (g x)))
어떤 법이 transpose
충족 되어야 합니까? 아마도
counit . transpose = fmap counit
cojoin . transpose = fmap transpose . transpose . fmap cojoin
또는 한 순서에서 다른 순서로 어떤 순서의 f와 g를 떼어내는 두 가지 방법이 동일한 결과를 제공하도록 보장하는 데 필요한 모든 것.
transpose
for Cursor
자체를 정의 할 수 있습니까 ? 전위의 일종을 얻을 수있는 한 가지 방법은 싸게주의하는 것입니다 Bwd
하고 Fwd
있습니다 zippily 실용적, 따라서 너무입니다 Cursor
.
instance Applicative Bwd where
pure x = pure x :< x
(fz :< f) <*> (sz :< s) = (fz <*> sz) :< f s
_ <*> _ = B0
instance Applicative Fwd where
pure x = x :> pure x
(f :> fs) <*> (s :> ss) = f s :> (fs <*> ss)
_ <*> _ = F0
instance Applicative Cursor where
pure x = Cur (pure x) x (pure x)
Cur fz f fs <*> Cur sz s ss = Cur (fz <*> sz) (f s) (fs <*> ss)
그리고 여기서 쥐 냄새를 맡기 시작해야합니다. 모양이 일치하지 않으면 잘림이 발생하며 , 이는 자체 조옮김이 자체 역전이라는 명백히 바람직한 속성을 깨뜨릴 것입니다. 어떤 종류의 비정형도 살아남지 못할 것입니다. 우리는 전치 연산자를 얻습니다 : sequenceA
, 그리고 완전히 정규적인 데이터의 경우 모든 것이 밝고 아름답습니다.
> regularMatrixCursor
Cur (B0 :< Cur (B0 :< 1) 2 (3 :> F0))
(Cur (B0 :< 4) 5 (6 :> F0))
(Cur (B0 :< 7) 8 (9 :> F0) :> F0)
> sequenceA regularMatrixCursor
Cur (B0 :< Cur (B0 :< 1) 4 (7 :> F0))
(Cur (B0 :< 2) 5 (8 :> F0))
(Cur (B0 :< 3) 6 (9 :> F0) :> F0)
그러나 내부 커서 중 하나를 정렬에서 벗어나더라도 (크기를 엉망으로 만들지 마십시오) 일이 잘못됩니다.
> raggedyMatrixCursor
Cur (B0 :< Cur ((B0 :< 1) :< 2) 3 F0)
(Cur (B0 :< 4) 5 (6 :> F0))
(Cur (B0 :< 7) 8 (9 :> F0) :> F0)
> sequenceA raggedyMatrixCursor
Cur (B0 :< Cur (B0 :< 2) 4 (7 :> F0))
(Cur (B0 :< 3) 5 (8 :> F0))
F0
하나의 외부 커서 위치와 여러 개의 내부 커서 위치가 있으면 잘 작동하는 조옮김이 없습니다. 자체 구성을 Cursor
사용하면 내부 구조가 서로 상대적으로 비정형이 될 수 있으므로 아니요 transpose
, 아니요 cojoin
. 당신은 정의 할 수 있고
instance (Comonad f, Traversable f, Comonad g, Applicative g) =>
Comonad (f :.: g) where
counit = counit . counit . unC
cojoin = C . fmap (fmap C . sequenceA) . cojoin . fmap cojoin . unC
그러나 내부 구조를 규칙적으로 유지하는 것은 우리에게 책임이 있습니다. 당신이 그 부담을 받아 들일 경우 때문에, 당신은, 반복 할 수 Applicative
및 Traversable
쉽게 구성에서 닫힙니다. 다음은 비트와 조각입니다.
instance (Functor f, Functor g) => Functor (f :.: g) where
fmap h (C fgx) = C (fmap (fmap h) fgx)
instance (Applicative f, Applicative g) => Applicative (f :.: g) where
pure = C . pure . pure
C f <*> C s = C (pure (<*>) <*> f <*> s)
instance (Functor f, Foldable f, Foldable g) => Foldable (f :.: g) where
fold = fold . fmap fold . unC
instance (Traversable f, Traversable g) => Traversable (f :.: g) where
traverse h (C fgx) = C <$> traverse (traverse h) fgx
편집 : 완전성을 위해 모든 것이 규칙적 일 때 수행하는 작업은 다음과 같습니다.
> cojoin (C regularMatrixCursor)
C {unC = Cur (B0 :< Cur (B0 :<
C {unC = Cur B0 (Cur B0 1 (2 :> (3 :> F0))) (Cur B0 4 (5 :> (6 :> F0)) :> (Cur B0 7 (8 :> (9 :> F0)) :> F0))})
(C {unC = Cur B0 (Cur (B0 :< 1) 2 (3 :> F0)) (Cur (B0 :< 4) 5 (6 :> F0) :> (Cur (B0 :< 7) 8 (9 :> F0) :> F0))})
(C {unC = Cur B0 (Cur ((B0 :< 1) :< 2) 3 F0) (Cur ((B0 :< 4) :< 5) 6 F0 :> (Cur ((B0 :< 7) :< 8) 9 F0 :> F0))} :> F0))
(Cur (B0 :<
C {unC = Cur (B0 :< Cur B0 1 (2 :> (3 :> F0))) (Cur B0 4 (5 :> (6 :> F0))) (Cur B0 7 (8 :> (9 :> F0)) :> F0)})
(C {unC = Cur (B0 :< Cur (B0 :< 1) 2 (3 :> F0)) (Cur (B0 :< 4) 5 (6 :> F0)) (Cur (B0 :< 7) 8 (9 :> F0) :> F0)})
(C {unC = Cur (B0 :< Cur ((B0 :< 1) :< 2) 3 F0) (Cur ((B0 :< 4) :< 5) 6 F0) (Cur ((B0 :< 7) :< 8) 9 F0 :> F0)} :> F0))
(Cur (B0 :<
C {unC = Cur ((B0 :< Cur B0 1 (2 :> (3 :> F0))) :< Cur B0 4 (5 :> (6 :> F0))) (Cur B0 7 (8 :> (9 :> F0))) F0})
(C {unC = Cur ((B0 :< Cur (B0 :< 1) 2 (3 :> F0)) :< Cur (B0 :< 4) 5 (6 :> F0)) (Cur (B0 :< 7) 8 (9 :> F0)) F0})
(C {unC = Cur ((B0 :< Cur ((B0 :< 1) :< 2) 3 F0) :< Cur ((B0 :< 4) :< 5) 6 F0) (Cur ((B0 :< 7) :< 8) 9 F0) F0} :> F0)
:> F0)}
Hancock의 Tensor 제품
규칙 성을 위해서는 구성보다 더 강한 것이 필요합니다. 당신은 "g-structures-all-the-same-shape의 f- 구조"의 개념을 포착 할 수 있어야합니다. 이것은 추정 할 수없는 Peter Hancock이 "tensor product"라고 부르는 것입니다. 제가 쓸 것입니다 f :><: g
. 하나의 "외부"f- 모양과 모든 내부 g- 구조에 공통 인 하나의 "내부"g- 모양이 있으므로 전치가 쉽게 정의 될 수 있습니다. 항상 자기 반대입니다. Hancock의 텐서는 Haskell에서 편리하게 정의 할 수는 없지만 종속 유형 설정에서는이 텐서를 갖는 "컨테이너"개념을 쉽게 공식화 할 수 있습니다.
아이디어를 제공하기 위해 컨테이너의 퇴보 개념을 고려하십시오.
data (:<|) s p x = s :<| (p -> x)
우리가 말하는 곳 s
은 "모양" p
의 유형과 "위치"의 유형입니다. 값은 모양의 선택과 x
각 위치 의 저장으로 구성됩니다 . 종속적 인 경우 위치 유형은 모양의 선택에 따라 달라질 수 있습니다 (예 : 목록의 경우 모양은 숫자 (길이)이고 그만큼 많은 위치가 있음). 이 컨테이너에는 텐서 제품이 있습니다.
(s :<| p) :><: (s' :<| p') = (s, s') :<| (p, p')
이것은 일반화 된 행렬과 같습니다. 한 쌍의 모양이 차원을 제공하고 각 위치 쌍에 요소가 있습니다. p
및의 p'
값을 입력 하고 의존 할 때이 작업을 완벽하게 수행 할 수 s
있으며 s'
, 이는 컨테이너의 텐서 곱에 대한 Hancock의 정의입니다.
Tensor 제품에 대한 InContext
고등학교에서 배운 수 있으므로 지금, ∂(s :<| p) = (s, p) :<| (p-1)
어디에 p-1
이상 적은 수의 요소를 몇 가지 유형입니다 p
. ∂ (s x ^ p) = (s p) * x ^ (p-1)과 같습니다. 한 위치를 선택 (모양에 기록)하고 삭제합니다. 걸림돌은 p-1
종속 유형없이 손을 잡는 것이 까다 롭다 는 것 입니다. 그러나 삭제하지 않고InContext
위치 를 선택 합니다 .
InContext (s :<| p) ~= (s, p) :<| p
이것은 종속 사례에서도 잘 작동하며 우리는
InContext (f :><: g) ~= InContext f :><: InContext g
이제 우리는 그것이 InContext f
항상 a 라는 것을 알고 있습니다. Comonad
이것은 InContext
s의 텐서 곱이 그 자체가 InContext
s 이기 때문에 코모 나딕이라는 것을 알려줍니다 . 즉, 차원 당 하나의 위치를 선택합니다 (전체적으로 정확히 하나의 위치를 제공함). 이전에는 하나의 외부 위치와 많은 내부 위치가있었습니다. 구성을 대체하는 텐서 제품으로 모든 것이 멋지게 작동합니다.
나 페리 안 펑터
그러나 Functor
텐서 곱과 구성이 일치 하는 하위 클래스가 있습니다. 이들은하다 Functor
의 f
하는 f () ~ ()
그래서 조성물에 누더기 값은 처음부터 배제되어 즉, 어쨌든 하나의 형태가있다 :. 이 Functor
들 모두 동형있는 (p ->)
몇 가지 위치 세트에 대해 p
우리가로 생각할 수 대수 (지수되는 x
줄 제기해야한다 f x
). 이에 따라 Hancock은 이러한 Naperian
펑터를 John Napier (Hancock이 사는 에딘버러 지역에 유령이있는 유령)의 이름을 따서 부릅니다 .
class Applicative f => Naperian f where
type Log f
project :: f x -> Log f -> x
positions :: f (Log f)
--- project positions = id
Naperian
펑은 유도 대수를 가지고 project
있다 찾아낸 요소 이온 함수 매핑 위치. Naperian
펑 모든 zippily이다 Applicative
으로 pure
그리고 <*>
돌출부에 대한 K 및 S 연결자에 대응. 또한 각 위치에서 해당 위치의 표현이 저장되는 값을 구성 할 수도 있습니다. 당신이 기억할 수있는 로그의 법칙이 즐겁게 나타납니다.
newtype Id x = Id {unId :: x} deriving Show
instance Naperian Id where
type Log Id = ()
project (Id x) () = x
positions = Id ()
newtype (:*:) f g x = Pr (f x, g x) deriving Show
instance (Naperian f, Naperian g) => Naperian (f :*: g) where
type Log (f :*: g) = Either (Log f) (Log g)
project (Pr (fx, gx)) (Left p) = project fx p
project (Pr (fx, gx)) (Right p) = project gx p
positions = Pr (fmap Left positions, fmap Right positions)
고정 크기 배열 ( 벡터 ) 은로 주어집니다 (Id :*: Id :*: ... :*: Id :*: One)
. 여기서는 One
로그가이고 상수 단위 펑터입니다 Void
. 그래서 배열은 Naperian
. 이제 우리는 또한
instance (Naperian f, Naperian g) => Naperian (f :.: g) where
type Log (f :.: g) = (Log f, Log g)
project (C fgx) (p, q) = project (project fgx p) q
positions = C $ fmap (\ p -> fmap (p ,) positions) positions
이는 다차원 배열이 Naperian
.
InContext f
for 의 버전을 구성하려면 Naperian f
위치를 가리 킵니다!
data Focused f x = f x :@ Log f
instance Functor f => Functor (Focused f) where
fmap h (fx :@ p) = fmap h fx :@ p
instance Naperian f => Comonad (Focused f) where
counit (fx :@ p) = project fx p
cojoin (fx :@ p) = fmap (fx :@) positions :@ p
따라서 특히 Focused
n 차원 배열은 실제로 코 모나드가 될 것입니다. 벡터의 구성은 벡터가이므로 n 벡터의 텐서 곱입니다 Naperian
. 그러나 Focused
n 차원 배열은 차원 을 결정 하는 n 개의 벡터 의 구성이 아닌 n- 겹 텐서 곱이 Focused
됩니다. 이 코 모나드를 지퍼로 표현하려면 텐서 곱을 구성 할 수있는 형태로 표현해야합니다. 나는 그것을 미래를위한 연습으로 남겨 둘 것이다.
pigworkers 게시물 및 http://hackage.haskell.org/packages/archive/representable-functors/3.0.0.1/doc/html/Data-Functor-Representable.html 에서 영감을 얻은 한 번 더 시도 하십시오 .
대표 가능 (또는 나 페리 안) 펑 터는 키 (또는 로그)가 모노 이드 인 경우 코 모나드 자체입니다! 그런 다음 coreturn
위치에서 값을 가져옵니다 mempty
. 그리고 cojoin
mappend
그것이 사용 가능한 두 개의 키입니다. (에 대한 comonad 인스턴스와 같습니다 (p ->)
.)
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
import Data.List (genericIndex)
import Data.Monoid
import Data.Key
import Data.Functor.Representable
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
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)
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
U
목록이 무한히 길면 표현 가능합니다. 그러면 모양이 하나뿐입니다. 의 키는 U n
n 개의 정수로 구성된 벡터입니다.
type instance Key (U n) = UKey n
data UKey (n :: Nat) where
P :: UKey Z
D :: Integer -> UKey n -> UKey (S n)
instance Lookup (U n) where lookup = lookupDefault
instance Indexable (U n) where
index (Point x) P = x
index (Dimension ls mid rs) (D i k)
| i < 0 = index (ls `genericIndex` (-i - 1)) k
| i > 0 = index (rs `genericIndex` ( i - 1)) k
| otherwise = index mid k
우리는 분할해야 Representable
이가지 경우, 하나의 인스턴스를 Z
하고 하나 S
우리는 유형의 값이 없기 때문에, U n
에 패턴 일치에있다.
instance Representable (U Z) where
tabulate f = Point (f P)
instance Representable (U n) => Representable (U (S n)) where
tabulate f = Dimension
(map (\i -> tabulate (f . D (-i))) [1..])
(tabulate (f . D 0))
(map (\i -> tabulate (f . D i)) [1..])
instance Monoid (UKey Z) where
mempty = P
mappend P P = P
instance Monoid (UKey n) => Monoid (UKey (S n)) where
mempty = D 0 mempty
mappend (D il kl) (D ir kr) = D (il + ir) (mappend kl kr)
그리고의 핵심 U n
은 실제로 monoid이므로 U n
representable-functor 패키지의 기본 구현을 사용하여 comonad로 전환 할 수 있습니다 .
instance (Monoid (UKey n), Representable (U n)) => Comonad (U n) where
coreturn = extractRep
cojoin = duplicateRep
(=>>) = flip extendRep
이번에는 몇 가지 테스트를했습니다.
testVal :: U (S (S Z)) Int
testVal = Dimension
(repeat (Dimension (repeat (Point 1)) (Point 2) (repeat (Point 3))))
(Dimension (repeat (Point 4)) (Point 5) (repeat (Point 6)))
(repeat (Dimension (repeat (Point 7)) (Point 8) (repeat (Point 9))))
-- Hacky Eq instance, just for testing
instance Eq x => Eq (U n x) where
Point a == Point b = a == b
Dimension la a ra == Dimension lb b rb = take 3 la == take 3 lb && a == b && take 3 ra == take 3 rb
instance Show x => Show (U n x) where
show (Point x) = "(Point " ++ show x ++ ")"
show (Dimension l a r) = "(Dimension " ++ show (take 2 l) ++ " " ++ show a ++ " " ++ show (take 2 r) ++ ")"
test =
coreturn (cojoin testVal) == testVal &&
fmap coreturn (cojoin testVal) == testVal &&
cojoin (cojoin testVal) == fmap cojoin (cojoin testVal)
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)
ReferenceURL : https://stackoverflow.com/questions/12963733/writing-cojoin-or-cobind-for-n-dimensional-grid-type
'developer tip' 카테고리의 다른 글
인증 된 (로그인 된) 사용자 세션으로 Scrapy 사용 (0) | 2020.12.31 |
---|---|
날짜 열이있는 데이터 프레임을 시계열로 변환 (0) | 2020.12.31 |
윤활유가있는 날짜 순서 (0) | 2020.12.31 |
Spring은 추상 클래스 내부에서 autowire 할 수 있습니까? (0) | 2020.12.31 |
Python에서 웹캠에 어떻게 액세스합니까? (0) | 2020.12.31 |