{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE InstanceSigs #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE NoStarIsType #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE QuantifiedConstraints #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} module FibSpec (main, spec) where import Data.IFunctor.Foldable import Data.Kind (Type) import Singlethongs import Test.Hspec import Test.QuickCheck data PeanoIdx = PeanoIdx singlethongs ''PeanoIdx main :: IO () main = hspec spec spec :: Spec spec = describe "fib using 'dyna'" $ do it "fibs" $ map fib [1 .. 8] `shouldBe` [1, 1, 2, 3, 5, 8, 13, 21] fib :: Integer -> Integer fib = getConst . fib' . Const where fib' :: Const Integer 'PeanoIdx -> Const Integer 'PeanoIdx fib' = dyna folder builder folder :: forall ix. SingI ix => PeanoF (ICofree PeanoF (Const Integer)) ix -> Const Integer ix folder OneF = 1 folder (SuccF (_ ::< OneF)) = 1 folder (SuccF (a ::< SuccF (b ::< _))) = a + b builder :: forall ix. SingI ix => Const Integer ix -> PeanoF (Const Integer) ix builder n = case sing :: Sing ix of SPeanoIdx -> if n <= 1 then OneF else SuccF (n - 1) data PeanoF f ix where OneF :: PeanoF f 'PeanoIdx SuccF :: f 'PeanoIdx -> PeanoF f 'PeanoIdx instance IFunctor PeanoF where imap _ OneF = OneF imap f (SuccF x) = SuccF (f x)