Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions examples/passing/RowNub.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module Main where

import Control.Monad.Eff.Console (log)
import Prim.Row (class Nub, class Union)
import Type.Row (RProxy(..))

nubUnion
:: forall r1 r2 r3 r4
. Union r1 r2 r3
=> Nub r3 r4
=> RProxy r1
-> RProxy r2
-> RProxy r4
nubUnion _ _ = RProxy

type InL = (x :: Int, y :: String)
type InR = (x :: String, y :: Int, z :: Boolean)
type Out = (x :: Int, y :: String, z :: Boolean)

test :: RProxy Out
test = nubUnion (RProxy :: RProxy InL) (RProxy :: RProxy InR)

main = log "Done"
3 changes: 3 additions & 0 deletions src/Language/PureScript/Constants.hs
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,9 @@ pattern Warn = Qualified (Just PrimTypeError) (ProperName "Warn")
pattern Union :: Qualified (ProperName 'ClassName)
pattern Union = Qualified (Just PrimRow) (ProperName "Union")

pattern Nub :: Qualified (ProperName 'ClassName)
pattern Nub = Qualified (Just PrimRow) (ProperName "Nub")

pattern RowCons :: Qualified (ProperName 'ClassName)
pattern RowCons = Qualified (Just PrimRow) (ProperName "Cons")

Expand Down
6 changes: 6 additions & 0 deletions src/Language/PureScript/Docs/Prim.hs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ primRowDocsModule = Module
, modComments = Just "The Prim.Row module is embedded in the PureScript compiler. Unlike `Prim`, it is not imported implicitly. It contains automatically solved classes for working with row types."
, modDeclarations =
[ union
, nub
, rowCons
]
, modReExports = []
Expand Down Expand Up @@ -287,6 +288,11 @@ union = primClassOf (P.primSubName "Row") "Union" $ T.unlines
, "The third type argument represents the union of the first two."
]

nub :: Declaration
nub = primClassOf (P.primSubName "Row") "Nub" $ T.unlines
[ "The Nub type class is used to remove duplicate labels from rows."
]

rowCons :: Declaration
rowCons = primClassOf (P.primSubName "Row") "Cons" $ T.unlines
[ "The Cons type class is a 4-way relation which asserts that one row of"
Expand Down
8 changes: 8 additions & 0 deletions src/Language/PureScript/Environment.hs
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ primRowTypes :: M.Map (Qualified (ProperName 'TypeName)) (Kind, TypeKind)
primRowTypes =
M.fromList
[ (primSubName "Row" "Union", (FunKind (Row kindType) (FunKind (Row kindType) (FunKind (Row kindType) kindType)), ExternData))
, (primSubName "Row" "Nub", (FunKind (Row kindType) (FunKind (Row kindType) kindType), ExternData))
, (primSubName "Row" "Cons", (FunKind kindSymbol (FunKind kindType (FunKind (Row kindType) (FunKind (Row kindType) kindType))), ExternData))
]

Expand Down Expand Up @@ -417,6 +418,13 @@ primRowClasses =
, FunctionalDependency [1, 2] [0]
, FunctionalDependency [2, 0] [1]
]))
-- class Nub (i :: # Type) (o :: # Type) | i -> o
, (primSubName "Row" "Nub", (makeTypeClassData
[ ("i", Just (Row kindType))
, ("o", Just (Row kindType))
] [] []
[ FunctionalDependency [0] [1]
]))
-- class RowCons (l :: Symbol) (a :: Type) (i :: # Type) (o :: # Type) | l i a -> o, l o -> a i
, (primSubName "Row" "Cons", (makeTypeClassData
[ ("l", Just kindSymbol)
Expand Down
14 changes: 13 additions & 1 deletion src/Language/PureScript/TypeChecker/Entailment.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import Control.Monad.Writer
import Data.Foldable (for_, fold, toList)
import Data.Function (on)
import Data.Functor (($>))
import Data.List (minimumBy, groupBy, sortBy)
import Data.List (minimumBy, groupBy, nubBy, sortBy)
import Data.Maybe (fromMaybe, mapMaybe)
import qualified Data.Map as M
import qualified Data.Set as S
Expand Down Expand Up @@ -57,6 +57,7 @@ data Evidence
| AppendSymbolInstance
| UnionInstance
| ConsInstance
| NubInstance
| RowToListInstance
deriving (Show, Eq)

Expand Down Expand Up @@ -190,6 +191,9 @@ entails SolverOptions{..} constraint context hints =
forClassName _ C.Union [l, r, u]
| Just (lOut, rOut, uOut, cst) <- unionRows l r u
= [ TypeClassDictionaryInScope [] 0 UnionInstance [] C.Union [lOut, rOut, uOut] cst ]
forClassName _ C.Nub [r, _]
| Just r' <- nubRows r
= [ TypeClassDictionaryInScope [] 0 NubInstance [] C.Nub [r, r'] Nothing ]
forClassName _ C.RowCons [TypeLevelString sym, ty, r, _]
= [ TypeClassDictionaryInScope [] 0 ConsInstance [] C.RowCons [TypeLevelString sym, ty, r, RCons (Label sym) ty r] Nothing ]
forClassName _ C.RowToList [r, _]
Expand Down Expand Up @@ -363,6 +367,7 @@ entails SolverOptions{..} constraint context hints =
return $ App (Abs (VarBinder nullSourceSpan UnusedIdent) valUndefined) e
mkDictionary UnionInstance _ = return valUndefined
mkDictionary ConsInstance _ = return valUndefined
mkDictionary NubInstance _ = return valUndefined
mkDictionary RowToListInstance _ = return valUndefined
mkDictionary (WarnInstance msg) _ = do
tell . errorMessage $ UserDefinedWarning msg
Expand Down Expand Up @@ -446,6 +451,13 @@ entails SolverOptions{..} constraint context hints =
, ty
, tl ]

nubRows :: Type -> Maybe Type
nubRows r =
guard (REmpty == rest) $>
rowFromList (nubBy ((==) `on` fst) fixed, rest)
where
(fixed, rest) = rowToSortedList r

-- Check if an instance matches our list of types, allowing for types
-- to be solved via functional dependencies. If the types match, we return a
-- substitution which makes them match. If not, we return 'Nothing'.
Expand Down