Skip to content

Instantly share code, notes, and snippets.

@quelgar
Last active February 22, 2017 14:54
Show Gist options
  • Save quelgar/4661081 to your computer and use it in GitHub Desktop.
Save quelgar/4661081 to your computer and use it in GitHub Desktop.
Is Javascript's array map function basically a comonadic cobind (=>> in Haskell)? Have a look as the jsmap function below.
-- Inspired by http://nedbatchelder.com/blog/201301/stupid_languages.html
-- which describes how the Javascript array.map function seems weird
-- and also http://blog.sigfpe.com/2008/03/comonadic-arrays.html
-- which describes the comonad for arrays
import Data.Array
import Data.Char
class Functor w => Comonad w where
(=>>) :: w a -> (w a -> b) -> w b
coreturn :: w a -> a
data Pointer i e = P i (Array i e) deriving Show
unpointer (P _ a) = a
instance Ix i => Functor (Pointer i) where
fmap f (P i a) = P i (fmap f a)
instance Ix i => Comonad (Pointer i) where
coreturn (P i a) = a ! i
P i a =>> f = P i $ listArray bds (fmap (f . flip P a) (range bds))
where bds = bounds a
-- Javascript's array mapping function
jsmap :: Array Int e -> (e -> Int -> Array Int e -> x) -> Array Int x
jsmap a f = let
g (P i a2) = f (a2 ! i) i a2
in unpointer $ (P 0 a) =>> g
readAsBase :: Num a => Int -> String -> a
readAsBase base = foldr (\c s -> s * base' + fromIntegral c) 0 . reverse . map c2i
where base' = fromIntegral base
c2i c = ord c - ord '0'
-- The JS parseInt has arity 2, but we add a third ignored argument to
-- mimic how JS silently throws away the extra argument in the original example
jsParseInt :: String -> Int -> ignored -> Double
jsParseInt s 0 _ = read s
jsParseInt s 1 _ = 0/0
jsParseInt s base _ = readAsBase base s
jsArray = listArray (0, 4) ["10", "10", "10", "10", "10"]
main = do
print $ show $ jsmap jsArray jsParseInt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment