packages feed

alms-0.6.0: src/Basis/Row.hs

module Basis.Row ( entries ) where

import Util
import BasisUtils
import Value
import AST

import qualified Data.Loc

entries :: [Entry Raw]
entries = [
    dec [sgQ| type `a ... |-> `b = {+ (`a -A> `b) ... +} |],
    fun "rowCase" -: [ty| ∀ `a `b. [ `a ] → (`a |-> `b) → `b |]
      -= \variant record → case variant of
           VaLab ix lab v → do
             f ← getField ix lab record
             vapp f v
           _ → throwFailure "case: expected variant",

    fun "isVariant"             -: [ty| ∀ `a. `a → bool |]
      -= \variant → case variant of
           VaLab _ _ _ → True
           _           → False,
    fun "variantLabel"          -: [ty| ∀ `a. [ `a ] → int * string |]
      -= \variant → case variant of
           VaLab ix lab _ → return (ix, show lab)
           _              → throwFailure "variantLabel: not a variant",
    fun "unsafeVariantValue"    -: [ty| ∀ `a `b. [ `a ] → `b |]
      -= \variant → case variant of
           VaLab _ _ v → return v
           _           → throwFailure "variantValue: not a variant",
    fun "unsafeMakeVariant"     -: [ty| ∀ `a `b. int → string → `a → [ `b ] |]
      -= \ix lab v → VaLab ix (ident lab) v,

    fun "isRecord"              -: [ty| ∀ `a. `a → bool |]
      -= \v → do
           case vprjM v of
             Just (AdditiveRecord _)       → True
             Just (MultiplicativeRecord _) → True
             _                             → False,
    fun "isAddRecord"      -: [ty| ∀ `a. `a → bool |]
      -= \v → do
           case vprjM v of
             Just (AdditiveRecord _)       → True
             _                             → False,
    fun "isMulRecord"      -: [ty| ∀ `a. `a → bool |]
      -= \v → do
           case vprjM v of
             Just (MultiplicativeRecord _) → True
             _                             → False,
    fun "recordLabels"          -: [ty| ∀ `a. {+ `a +} → string list |]
      -= \v → do
           record ← vprjM v
           case record of
             AdditiveRecord fields       → map (show . uidToLid . fst) fields
             MultiplicativeRecord fields → map (show . uidToLid . fst) fields,
    fun "unsafeGetRecordField"
          -: [ty| ∀ `a `b. int → string → { `a } → `b |]
      -= \ix lab v → getField ix (lidToUid (ident lab)) v,
    fun "unsafeGetRecordFieldThunk"
          -: [ty| ∀ `a `b. int → string → {+ `a +} → unit → `b |]
      -= \ix lab v → do
           io ← getFieldThunk ix (lidToUid (ident lab)) v
           return (VaFun (FNAnonymous []) (\_ → io)),
    fun "unsafeRecordAddField"
          -: [ty| ∀ `a `b `c. string → `a → { `b } → { `c } |]
      -= \lab v1 v2 → do
           MultiplicativeRecord fields ← vprjM v2
           return . vinj . MultiplicativeRecord $
             (lidToUid (ident lab), v1) : fields
             ∷ IO Value,
    fun "unsafeRecordAddFieldThunk"
          -: [ty| ∀ `a `b `c. string → (unit -A> `a) → {+ `b +} → {+ `c +} |]
      -= \lab thunk v2 → do
           AdditiveRecord fields ← vprjM v2
           return . vinj . AdditiveRecord $
             (lidToUid (ident lab),
              (vapp thunk (vinj ()), vppr thunk)) : fields
             ∷ IO Value,
    fun "unsafeRecordRemoveField"
          -: [ty| ∀ `a `b `q. string → (`q, `a) record → (`q, `b) record |]
      -= \lab v → do
           record ← vprjM v
           return . vinj $ case record of
             AdditiveRecord fields       →
              AdditiveRecord (remField (lidToUid (ident lab)) fields)
             MultiplicativeRecord fields →
              MultiplicativeRecord (remField (lidToUid (ident lab)) fields)
           ∷ IO Value
  ]

getField ∷ Int → Uid Renamed → Value → IO Value
getField = join <$$$> getFieldThunk

getFieldThunk ∷ Int → Uid Renamed → Value → IO (IO Value)
getFieldThunk ix0 lab v = do
  record ← vprjM v
  case record of
    AdditiveRecord fields       → fst <$> findNth ix0 fields
    MultiplicativeRecord fields → return <$> findNth ix0 fields
  where
  findNth _  []         = throwFailure "record field not found"
  findNth ix ((lab', v'):fields')
    | lab == lab'       = if ix == 0
                            then return v'
                            else findNth (ix - 1) fields'
    | otherwise         = findNth ix fields'

remField ∷ Uid Renamed → [(Uid Renamed, v)] → [(Uid Renamed, v)]
remField _ []           = []
remField k ((k',v'):kvs)
  | k == k'             = kvs
  | otherwise           = (k',v') : remField k kvs