Skip to content

Instantly share code, notes, and snippets.

@fredyr
Last active January 1, 2016 10:56
Show Gist options
  • Save fredyr/7fec131dded5ff8a133e to your computer and use it in GitHub Desktop.
Save fredyr/7fec131dded5ff8a133e to your computer and use it in GitHub Desktop.
Persistent vector in Purescript
-- Playing around with persistent vectors in Purescript
-- Imitiates the interface from Data.Array, but uses Mori.js persistent
-- vector implementation e.g. to avoid copy-on-write etc.
module Data.Vector where
import Data.Maybe
-- LOL I have no idea what I'm doing, but reverse engineering from the
-- JS output, this actually seems to work
foreign import data Mori :: *
foreign import data Vec :: * -> *
foreign import data Seq :: * -> *
foreign import mori "var mori = require('mori/mori.js')" :: Mori
foreign import vecToString
"function vecToString(vec) {\
\ return vec.toString();\
\}" :: forall a. Vec a -> String
instance showVec :: Show (Vec a) where
show = vecToString
foreign import seqToString
"function seqToString(seq) {\
\ return seq.toString();\
\}" :: forall a. Seq a -> String
instance showSeq :: Show (Seq a) where
show = seqToString
singleton e = vector [e]
empty = vector []
foreign import arrayToVector
"function arrayToVector(vec) {\
\ return mori.into(mori.vector(), vec);\
\}" :: forall a. [a] -> Vec a
foreign import seqToVector
"function seqToVector(vec) {\
\ return mori.into(mori.vector(), vec);\
\}" :: forall a. Seq a -> Vec a
foreign import vectorToArray
"function vectorToArray(vec) {\
\ return mori.into_array(vec);\
\}" :: forall a. Vec a -> [a]
foreign import seqToArray
"function seqToArray(vec) {\
\ return mori.into_array(vec);\
\}" :: forall a. Seq a -> [a]
-- Make Arrays from Vec and Seq
class ToArray c a where
array :: forall a. c a -> [a]
instance vecToArr :: ToArray Vec a where
array = vectorToArray
instance seqToArr :: ToArray Seq a where
array = seqToArray
-- Make Vec's from Array and Seq
class ToVector c a where
vector :: forall a. c a -> Vec a
instance arrToVec :: ToVector Array a where
vector = arrayToVector
instance seqToVec :: ToVector Seq a where
vector = seqToVector
foreign import length
"function length(vec) {\
\ return mori.count(vec);\
\}" :: forall a. Vec a -> Number
foreign import snoc
"function snoc(vec) {\
\ return function(e) {\
\ return mori.conj(vec, e);\
\ }\
\}" :: forall a. Vec a -> a -> Vec a
foreign import unsafeHead
"function unsafeHead(vec) {\
\ return mori.first(vec);\
\}" :: forall a. Vec a -> a
foreign import unsafeLast
"function unsafeLast(vec) {\
\ return mori.peek(vec);\
\}" :: forall a. Vec a -> a
foreign import unsafeTail
"function unsafeTail(vec) {\
\ return mori.rest(vec);\
\}" :: forall a. Vec a -> Seq a
foreign import unsafeInit
"function unsafeInit(vec) {\
\ return mori.pop(vec);\
\}" :: forall a. Vec a -> Seq a
head :: forall a. Vec a -> Maybe a
head xs = if length xs > 0
then Just $ unsafeHead xs
else Nothing
last :: forall a. Vec a -> Maybe a
last xs = if length xs > 0
then Just $ unsafeLast xs
else Nothing
tail :: forall a. Vec a -> Maybe (Seq a)
tail xs = if length xs > 0
then Just $ unsafeTail xs
else Nothing
init :: forall a. Vec a -> Maybe (Seq a)
init xs = if length xs > 0
then Just $ unsafeInit xs
else Nothing
foreign import unsafeIndex
"function unsafeIndex(arr) {\
\ return function(idx) {\
\ return mori.get(arr, idx);\
\ }\
\}" :: forall a. Vec a -> Number -> a
infixl 8 !!
(!!) :: forall a. Vec a -> Number -> Maybe a
(!!) xs n =
if n < 0 || n >= (length xs) || isInt n
then Nothing
else Just (xs `unsafeIndex` n)
where
isInt n = n /= complement (complement n)
-- Should be polymorphic, can take Seqs or Vecs and returns a Seq
foreign import append
"function append(u) {\
\ return function(v) {\
\ return mori.concat(u, v);\
\ }\
\}" :: forall a. Vec a -> Vec a -> Seq a
foreign import concat
"function concat(vs) {\
\ return mori.flatten(vs);\
\}" :: forall a. Vec (Vec a)-> Seq a
foreign import drop
"function drop(n) {\
\ return function(v) {\
\ return mori.drop(n, v);\
\ }\
\}" :: forall a. Number -> Vec a -> Seq a
foreign import take
"function take(n) {\
\ return function(v) {\
\ return mori.take(n, v);\
\ }\
\}" :: forall a. Number -> Vec a -> Seq a
-- Should be polymorphic for all `Seqable`
foreign import map
"function map(f) {\
\ return function(vec) {\
\ return mori.map(f, vec);\
\ }\
\}" :: forall a b. (a -> b) -> Vec a -> Seq b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment