{-# LANGUAGE OverloadedStrings #-} module Funcons.Operations.Lists where import Funcons.Operations.Internal import Funcons.Operations.Booleans import Data.Maybe (isJust, fromJust) library :: HasValues t => Library t library = libFromList [ ("lists", UnaryExpr lists) , ("list-singleton", UnaryExpr list_singleton) , ("list", NaryExpr list_) , ("list-append", BinaryExpr list_append) , ("list-concat", NaryExpr list_concat) , ("nil", NullaryExpr nil) , ("cons", BinaryExpr cons) , ("is-nil", UnaryExpr is_nil) , ("head", UnaryExpr headOp) , ("tail", UnaryExpr tailOp) ] lists_ :: HasValues t => [OpExpr t] -> OpExpr t lists_ = unaryOp lists lists :: HasValues t => OpExpr t -> OpExpr t lists = UnaryOp "lists" (Normal . injectT . ADT "lists" . (:[])) list_singleton_ :: HasValues t => [OpExpr t] -> OpExpr t list_singleton_ = unaryOp list_singleton list_singleton :: HasValues t => OpExpr t -> OpExpr t list_singleton = vUnaryOp "list-singleton" (Normal . inject . list . (:[])) nil_ :: HasValues t => [OpExpr t] -> OpExpr t nil_ = nullaryOp nil nil :: HasValues t => OpExpr t nil = NullaryOp "nil" (Normal $ inject $ list []) is_nil_ :: HasValues t => [OpExpr t] -> OpExpr t is_nil_ = unaryOp is_nil is_nil :: HasValues t => OpExpr t -> OpExpr t is_nil = UnaryOp "is-nil" op where op xs | Just lv <- project xs = case lv of ADTVal "list" [] -> Normal $ inject $ true_ _ -> Normal $ inject $ false_ | otherwise = ProjErr "is-nil" cons_ :: HasValues t =>[OpExpr t] -> OpExpr t cons_ = binaryOp cons cons :: HasValues t => OpExpr t -> OpExpr t -> OpExpr t cons = vBinaryOp "cons" op where op v lv = case lv of ADTVal "list" xs -> Normal $ inject $ ADTVal "list" (inject v:xs) _ -> SortErr"cons should be given a value and a list" list_ :: HasValues t => [OpExpr t] -> OpExpr t list_ = vNaryOp "list" (Normal . inject . list) list_append_ :: HasValues t => [OpExpr t] -> OpExpr t list_append_ = binaryOp list_append list_append :: HasValues t => OpExpr t -> OpExpr t -> OpExpr t list_append = vBinaryOp "list-append" op where op (ADTVal "list" l1) (ADTVal "list" l2) = Normal $ inject $ ADTVal "list" (l1 ++ l2) op _ _ = SortErr "list-append not applied to two lists" isList (ADTVal "list" l) = all (isJust) $ map project l isList _ = False toList (ADTVal "list" l) = map (fromJust . project) l toList _ = error "list-append 1" list_concat_ :: HasValues t => [OpExpr t] -> OpExpr t list_concat_ = list_concat list_concat :: HasValues t => [OpExpr t] -> OpExpr t list_concat = vNaryOp "list-concat" op where op args | all isList args = Normal $ inject $ list $ concatMap toList args | otherwise = SortErr "list-concat not applied to lists" head_, tail_ :: HasValues t => [OpExpr t] -> OpExpr t head_ = unaryOp headOp tail_ = unaryOp tailOp headOp,tailOp :: HasValues t => OpExpr t -> OpExpr t headOp = vUnaryOp "head" op where op (ADTVal "list" []) = DomErr "head of empty list" op (ADTVal "list" (x:xs)) = Normal x op _ = SortErr "head not applied to a list" tailOp = vUnaryOp "tail" op where op (ADTVal "list" []) = DomErr "tail of empty list" op (ADTVal "list" (x:xs)) = Normal $ inject (ADTVal "list" xs) op _ = SortErr "tail not applied to a list"