-
Notifications
You must be signed in to change notification settings - Fork 71
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #418 from JordanMartinez/development
Make next minor release: PS-0.13.x-v0.21.1
- Loading branch information
Showing
19 changed files
with
2,053 additions
and
1,253 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
120 changes: 120 additions & 0 deletions
120
11-Syntax/01-Basic-Syntax/src/03-TypeClasses-and-Newtypes/08-Instance-Chains.purs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
module Syntax.Basic.Typeclass.InstanceChains where | ||
|
||
-- ## Instance Chains: Syntax | ||
|
||
import Prelude -- imports the '+' operation below... | ||
|
||
data Type1 = Type1 | ||
data Type2 = Type2 | ||
data Type3 = Type3 | ||
|
||
class ExampleClass1 theType | ||
|
||
-- Instance chains are a workaround to the problem of "overlapping instances." | ||
-- Here's how the syntax works: | ||
instance name1 :: ExampleClass1 Type1 | ||
else instance name2 :: ExampleClass1 Type2 | ||
-- ... | ||
else instance name3 :: ExampleClass1 Type3 | ||
|
||
-- For readability, the `else` and `instance` keywords can appear on | ||
-- their own line or with a newline separating the keywords | ||
class ExampleClass2 theType | ||
|
||
instance nameA :: ExampleClass2 Type1 | ||
else | ||
instance nameB :: ExampleClass2 Type2 | ||
else | ||
|
||
instance nameC :: ExampleClass2 Type3 | ||
|
||
-- ## Instance Chains: Use Cases | ||
|
||
-- Instance chains are useful because they allow you to define multiple | ||
-- instances for a given type class, but define the order in which the | ||
-- type class constraint is solved. | ||
|
||
data SomeRandomType | ||
= FirstValue | ||
| SecondValue | ||
|
||
class ProduceAnInt a where | ||
mkInt :: a -> Int | ||
|
||
-- When solving for `ProduceAnInt someType`, the compiler will | ||
-- solve for `someType` in the following order: | ||
instance tryMeFirst :: ProduceAnInt Int where | ||
mkInt theInt = theInt | ||
else | ||
instance tryMeSecond :: ProduceAnInt String where | ||
mkInt _ = 13 | ||
else | ||
instance tryMeThird :: ProduceAnInt SomeRandomType where | ||
mkInt FirstValue = 89 | ||
mkInt SecondValue = 98 | ||
else | ||
instance catchAll :: ProduceAnInt allOtherPossibleTypes where | ||
mkInt _ = 42 | ||
|
||
data HasNoInstance = HasNoInstance | ||
|
||
example :: Int | ||
example = | ||
(mkInt 1 ) + (mkInt "foo") + (mkInt FirstValue) + (mkInt HasNoInstance) {- | ||
which, once the constraints are solved, will be the same as computing | ||
(1) + (13) + (89) + (42) -} | ||
|
||
|
||
-- ## Instance Chains Gotchas: No Backtracking | ||
|
||
-- Given the following type class | ||
|
||
class Stringify a where | ||
stringify :: a -> String | ||
|
||
-- One might write an instance chain like so with the following idea: | ||
-- 1. First attempt to show the item using that type class instance | ||
-- 2. Otherwise, indicate that it cannot be shown. | ||
|
||
instance doMeFirst :: (Show allPossibleTypes) => Stringify allPossibleTypes where | ||
stringify a = show a | ||
else | ||
instance defaultToMeOtherwise :: Stringify a where | ||
stringify _ = "The value could not be converted into a String." | ||
|
||
-- Then, one might attempt to use that code like so: | ||
data Foo = Foo | ||
|
||
-- failsToCompile :: String | ||
-- failsToCompile = stringify "a normal string" <> stringify Foo | ||
|
||
{- | ||
Uncommenting that will produce the following compiler error: | ||
No type class instance was found for | ||
Data.Show.Show Foo | ||
while applying a function stringify | ||
of type Stringify t0 => t0 -> String | ||
to argument Foo | ||
while checking that expression stringify Foo | ||
has type String | ||
in value declaration failsToCompile | ||
where t0 is an unknown type | ||
-} | ||
|
||
-- Why does this occur? Because the `doMeFirst` instance will match on | ||
-- every type since the parameter passed to Stringify is literally | ||
-- `allPossibleTypes`. It will then attempt to find the `Show` instance | ||
-- for `allPossibleTypes`. In the case of `Foo`, which does not | ||
-- have such an instance, the compiler does not "backtrack" and | ||
-- attempt to use the `defaultToMeOtherwise` instance. Rather, it immediately | ||
-- fails with the above error. | ||
-- Backtracking is a feature that has not yet been implemented in the | ||
-- compiler. |
3 changes: 3 additions & 0 deletions
3
11-Syntax/01-Basic-Syntax/src/03-TypeClasses-and-Newtypes/31-Gotchas.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Gotchas | ||
|
||
The rest of this folder will cover a few "gotchas" that can occur when you're working with type classes. Some of the code in these examples will be commented out because it will fail to compile. |
67 changes: 67 additions & 0 deletions
67
...yntax/01-Basic-Syntax/src/03-TypeClasses-and-Newtypes/32-Type-Equality-Not-Propagate.purs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
module Syntax.Basic.Typeclass.Gotchas.TypeEqualityNotPropagate where | ||
|
||
import Unsafe.Coerce (unsafeCoerce) | ||
|
||
-- ## Gotcha Number 1: Type Equality isn't yet included in Type Class Constraints | ||
|
||
-- ### Example of the Problem | ||
|
||
-- Given a type class like so... | ||
class TwoTypesButTheyAreTheSameThing a b | a -> b, b -> a | ||
|
||
-- and an instance like so... | ||
instance exampleTypeClass :: TwoTypesButTheyAreTheSameThing Int Int | ||
|
||
-- ... the below code will fail to compile | ||
{- | ||
foo :: forall int | ||
. TwoTypesButTheyAreTheSameThing Int int | ||
=> int | ||
foo = 8 | ||
Compiler Error: | ||
Could not match type | ||
Int | ||
with type | ||
int0 | ||
while checking that type Int | ||
is at least as general as type int0 | ||
while checking that expression 8 | ||
has type int0 | ||
in value declaration foo | ||
where sameAsInt0 is a rigid type variable | ||
bound at (line 9, column 7 - line 9, column 8) | ||
-} | ||
|
||
-- Why? Because the compiler does not also infer that `int` must be | ||
-- the type, `Int`, when solving the type class constraint, even if the | ||
-- instance and type class' functional dependencies indicate otherwise. | ||
|
||
-- ### Current Workaround | ||
|
||
class A_Determines_B a b | a -> b | ||
|
||
instance aDeterminesB :: A_Determines_B Int String | ||
|
||
-- The below "foreign import" syntax will be covered more in the FFI folder | ||
foreign import data Computed :: Type -> Type | ||
|
||
fromComputed :: forall a b. A_Determines_B a b => Computed a -> b | ||
fromComputed = unsafeCoerce | ||
|
||
toComputed :: forall a b. A_Determines_B a b => b -> Computed a | ||
toComputed = unsafeCoerce | ||
|
||
-- As hdgarood explained it, | ||
-- "This is safe because you have to tell the compiler that you have an | ||
-- `A_Determines_B a b` instance before it will coerce between the `a` and `b`. | ||
-- But yes it’s expected that constraints with fundeps don’t propagate | ||
-- type equalities. That’s not yet implemented." |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
# Foldable Traversable | ||
|
||
This folder is still a Work In Progress because it originally existed in a different location in this repository. | ||
This folder will overview the `purescript-foldable-traversable` and `purescript-filterable` libraries. Together, these libraries provide most of the functions one would use when working with collections. | ||
|
||
These two type classes are being overviewed because their concepts will arise later in the "Hello World" folder. Rather than explaining them there when we need them, we'll explain them here so that they are more familiar when we get to them there. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.