👻

# Concept This is a package designed to help optimize around scenarios with bad newtype support without losing type safety.
```haskell Spooky :: (s :: Type) -> (a :: Type) -> Type ``` If type `a` can be represented as type `s`, we can make `s` spooky. While we usually might use terms of type `a`, we need to represent `a` as a term of type `s` instead because of some tragedy. Converting our types to `s` directly loses important type information (knowledge of `a` is erased). We could preserve this information by placing `a` in a phantom typed newtype over `s`. But then we incuring cost around this newtype, that is not incurred by a type alias. However, if we use a type alias over `s` to get `a` into a phantom type, we get no additional safety over using `s` directly. Only readability is gained with the type alias. **This library resolves this tension** `Data.Spooky.Spooky` is a newtype or a type alias depending on cabal flags. This means you can develop with Spooky as a newtype and get all the benefits of the static type checking and static analysis in tooling, while for production use a type alias. This technique was originally motivated by the need to reduce file sizes when using the Haskell to Plutus compiler in 2021. # The Typed Version This **is** the default. You may pass a cabal flag `-f typed` for symmetry, but it wont do anything. ```haskell newtype Spooky (s :: Type) (a :: Type) = Spooky s ``` ## Note Keep in mind with the typed version the following works. So we have some real safety: ```haskell λ. newtype Typed a = Typed String deriving Show λ. typedId = id :: Typed Int -> Typed Int λ. y = Typed "wat" :: Typed String λ. typedId y :21:9: error: • Couldn't match type ‘[Char]’ with ‘Int’ Expected type: Typed Int Actual type: Typed String • In the first argument of ‘typedId’, namely ‘y’ In the expression: typedId y In an equation for ‘it’: it = typedId y ``` # Untyped Version This is **not** the default. Supplied along side the newtyped version, and can be enabled with a cabal flag. ```bash cabal build -f untyped ``` will replace the newtype with an alias ```haskell type Spooky (s :: Type) (a :: Type) = s ``` This allows for some safety as we can hold type information in the phantom type representing the semantics of our code. ## Note Keep in mind the following works. So not that much safety is provided here: ```haskell λ. type Untyped a = String λ. untypedId = id :: Untyped Int -> Untyped Int λ. x = "wat" :: Untyped String λ. untypedId x "wat" ```