| | 104 | op1Uniq v = do |
| | 105 | -- We want to have a real Haskell list |
| | 106 | args <- fromVal v |
| | 107 | -- Extract our comparator sub, or Nothing if none was specified |
| | 108 | (valList, cmp) <- case args of |
| | 109 | (v:vs) -> do |
| | 110 | ifValTypeIsa v "Code" |
| | 111 | (return (vs, Just v)) |
| | 112 | (ifValTypeIsa (last args) "Code" |
| | 113 | (return (init args, Just $ last args)) |
| | 114 | (return (args, Nothing))) |
| | 115 | _ -> return (args, Nothing) |
| | 116 | -- After this parameter unpacking, we begin doing the real work. |
| | 117 | op1Uniq' cmp valList |
| | 118 | where |
| | 119 | op1Uniq' :: (Maybe Val) -> [Val] -> Eval Val |
| | 120 | -- If the user didn't specify an own comparasion sub, we can simply use |
| | 121 | -- Haskell's nub. |
| | 122 | op1Uniq' Nothing valList = return . VList $ nub valList |
| | 123 | -- Else, we have to write our own nubByM and use that. |
| | 124 | op1Uniq' (Just subVal) valList = do |
| | 125 | sub <- fromVal subVal |
| | 126 | evl <- asks envEval |
| | 127 | -- Here we execute the user's sub |
| | 128 | result <- nubByM (\a b -> do |
| | 129 | rv <- local (\e -> e{ envContext = cxtItem "Bool" }) $ do |
| | 130 | evl (App (Val sub) [Val a, Val b] []) |
| | 131 | -- The sub returns either true or false. |
| | 132 | bool <- fromVal rv |
| | 133 | return . VBool $ bool) valList |
| | 134 | return . VList $ result |
| | 135 | -- This is the same as nubBy, only lifted into the Eval monad |
| | 136 | nubByM :: (Val -> Val -> Eval Val) -> [Val] -> Eval [Val] |
| | 137 | nubByM eq l = nubByM' l [] |
| | 138 | where |
| | 139 | nubByM' [] _ = return [] |
| | 140 | nubByM' (y:ys) xs = do |
| | 141 | -- elemByM returns a Val, but we need a VBool, so we have to use fromVal. |
| | 142 | cond <- fromVal =<< elemByM eq y xs |
| | 143 | if cond then nubByM' ys xs else do |
| | 144 | result <- nubByM' ys (y:xs) |
| | 145 | return (y:result) |
| | 146 | elemByM :: (Val -> Val -> Eval Val) -> Val -> [Val] -> Eval Val |
| | 147 | elemByM _ _ [] = return . VBool $ False |
| | 148 | elemByM eq y (x:xs) = do |
| | 149 | cond <- fromVal =<< eq x y |
| | 150 | -- Same here (we need a VBool, not a Var). |
| | 151 | if cond then return . VBool $ cond else elemByM eq y xs |
| | 152 | |