👻
# 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"
```