Skip to content

Instantly share code, notes, and snippets.

@cdparks
Created September 7, 2017 21:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cdparks/849810cb7896beb82f998cb308e06f23 to your computer and use it in GitHub Desktop.
Save cdparks/849810cb7896beb82f998cb308e06f23 to your computer and use it in GitHub Desktop.
But Why Though
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
import Control.Monad
import Control.Exception
import GHC.Exts
import GHC.IO
import GHC.Prim
import System.IO.Unsafe
data UntypedArray =
UntypedArray
{ _size :: Int#
, _array :: SmallArray# Any
}
empty :: UntypedArray
empty =
unsafePerformIO $! IO $ \s0 ->
case newSmallArray# 0# (error "empty") s0 of
(# s1, arr0 #) ->
case unsafeFreezeSmallArray# arr0 s1 of
(# s2, arr1 #) -> (# s2, UntypedArray 0# arr1 #)
append :: UntypedArray -> a -> UntypedArray
append (UntypedArray size arr0) a =
let
newSize = size +# 1#
in
unsafePerformIO $! IO $ \s0 ->
case newSmallArray# newSize (error "append") s0 of
(# s1, arr1 #) ->
case copySmallArray# arr0 0# arr1 0# size s1 of
s2 ->
case writeSmallArray# arr1 size (unsafeCoerce# a) s2 of
s3 ->
case unsafeFreezeSmallArray# arr1 s3 of
(# s4, arr2 #) -> (# s4, UntypedArray newSize arr2 #)
infixl 5 |>
(|>) :: UntypedArray -> a -> UntypedArray
(|>) = append
prepend :: a -> UntypedArray -> UntypedArray
prepend a (UntypedArray size arr0) =
let
newSize = size +# 1#
in
unsafePerformIO $! IO $ \s0 ->
case newSmallArray# newSize (error "prepend") s0 of
(# s1, arr1 #) ->
case copySmallArray# arr0 0# arr1 1# size s1 of
s2 ->
case writeSmallArray# arr1 0# (unsafeCoerce# a) s2 of
s3 ->
case unsafeFreezeSmallArray# arr1 s3 of
(# s4, arr2 #) -> (# s4, UntypedArray newSize arr2 #)
infixr 5 <|
(<|) :: a -> UntypedArray -> UntypedArray
(<|) = prepend
get :: forall a. Int -> UntypedArray -> a
get (I# index) (UntypedArray _ arr0) =
unsafePerformIO $! IO $ \s0 ->
case unsafeThawSmallArray# arr0 s0 of
(# s1, arr1 #) ->
case readSmallArray# arr1 index s1 of
(# s2, a #) -> (# s2, unsafeCoerce# a #)
set :: forall a. Int -> a -> UntypedArray -> UntypedArray
set (I# index) a (UntypedArray size arr0) =
unsafePerformIO $! IO $ \s0 ->
case newSmallArray# size (error "set") s0 of
(# s1, arr1 #) ->
case copySmallArray# arr0 0# arr1 0# size s1 of
s2 ->
case writeSmallArray# arr1 index (unsafeCoerce# a) s2 of
s3 ->
case unsafeFreezeSmallArray# arr1 s3 of
(# s4, arr2 #) -> (# s4, UntypedArray size arr2 #)
expect :: Bool -> IO ()
expect cond = void (evaluate (assert cond ()))
main :: IO ()
main = do
let xs = empty |> id @Int 1 |> True |> "hello!" |> id @Double 3.14
expect $ get @Int 0 xs == 1
expect $ get @Bool 1 xs == True
expect $ get @String 2 xs == "hello!"
expect $ get @Double 3 xs == 3.14
expect $ get @Bool 0 (set 0 False xs) == False
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment