Last active
January 1, 2016 10:56
-
-
Save fredyr/7fec131dded5ff8a133e to your computer and use it in GitHub Desktop.
Persistent vector in Purescript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- 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