These are chat archives for ramda/ramda

18th
May 2015
Simon Friis Vindum
@paldepind
May 18 2015 08:40
Hello! I've just revamped the readme of unon-type-js. It should be much more descriptive now – but please tell me if anything is unclear. I've also made case associated with a type so that it will throw if passed an incorrect type.
Hardy Jones
@joneshf
May 18 2015 09:25
very nice
now push ramda-fantasy to use it :)
Hardy Jones
@joneshf
May 18 2015 09:40
You should add a polymorphic example.
Something like:
// Product : a -> b -> Product a b
var Product = Type({
  Product: [R.T, R.T]
});
// InL : a -> Sum a b
// InR : b -> Sum a b
var Sum = Type({
  InL: [R.T],
  InR: [R.T]
});
Simon Friis Vindum
@paldepind
May 18 2015 09:47
Hm. What is the use case for that?

What about:

var Maybe = (a) => Type({Nothing: [], Just: [a]});

A type constructor for a maybe type.

Hardy Jones
@joneshf
May 18 2015 09:48
for polymorphism in general?
or those examples in specific?
Simon Friis Vindum
@paldepind
May 18 2015 09:48
No. That specific example?

Type constructor for a tree with values of type a:

var Tree = (a) => Type({Empty: [], Leaf: [a, Tree(a), Tree(a)]})

I'm not sure it works though ;)

Due to the recursion.
Hardy Jones
@joneshf
May 18 2015 09:52

just two of the primitives of adts, sum and product types.

For instance

var Unit = Type({Unit: []});
var nothing = Sum.InL(Unit.Unit());
var just = (x) => Sum.InR(x);
yeah, i couldnt' get cons lists to work
kept getting: TypeError: wrong value passed to location 1 in Cons
Simon Friis Vindum
@paldepind
May 18 2015 09:53
How did you define it?
Hardy Jones
@joneshf
May 18 2015 09:54
coffee> List = Type({Nil: [], Cons: [R.T, List]})
{ Nil: [Function], Cons: [Function], case: [Function] }
coffee> List.Nil()
[ of: { Nil: [Function], Cons: [Function], case: [Function] },
  name: 'Nil' ]
coffee> List.Cons(1, List.Nil())
/home/joneshf/node_modules/union-type-js/union-type.js:32
        throw new TypeError('wrong value ' + v + ' passed to location ' + i + 
              ^
TypeError: wrong value  passed to location 1 in Cons
Simon Friis Vindum
@paldepind
May 18 2015 09:56
It makes sense though. List is not defined when you pass it to Type.
Hardy Jones
@joneshf
May 18 2015 09:56
yeah
Seb Insua
@sebinsua
May 18 2015 09:56
I had the funniest edge case the other day. I found some code that was trying to check whether R.__ was R.is(Function) or not.
Simon Friis Vindum
@paldepind
May 18 2015 10:23

@joneshf Ta da! It's black magic but cons lists now work!!

var List = Type({Nil: [], Cons: [R.T, List]});
var toString = List.case({
  Cons: (head, tail) => head + ' : ' + toString(tail),
  Nil: () => 'Nil',
});

And using it:

var list = List.Cons(1, List.Cons(2, List.Cons(3, List.Nil())));
console.log(toString(list)); // => '1 : 2 : 3 : Nil'

The toString function is just an example. A map function could just as easily have been made.

When List is used in the definition of List it is still undefined. So I simply interpret undefined as meaning "recursively of the type currently being defined". It works splendidly. And if people accidentally pass undefined to Type the error message will still be very descriptive.
Hardy Jones
@joneshf
May 18 2015 10:50
nice!
Simon Friis Vindum
@paldepind
May 18 2015 10:56
Next step is recursive type constructors like my Tree example before :)
Scott Christopher
@scott-christopher
May 18 2015 11:13
You could alternatively have a sentinel object like a Type.Self that could be passed in to mark it as a reference to itself.
Simon Friis Vindum
@paldepind
May 18 2015 11:19
@scott-christopher I thought about that as well. But this reads really well and I don't see any real downsides?
Scott Christopher
@scott-christopher
May 18 2015 11:22
The only thing I can think of (and it's a bit of a stretch) is it always requires assigning it to a named variable, so something such as this won't be possible: module.exports = Type({Nil: [], Cons: [R.T, List]});
Definitely not a deal-breaker, because you could always declare the variable prior to assigning to module.exports, but just a caveat to be mindful of.
Simon Friis Vindum
@paldepind
May 18 2015 13:03

@scott-christopher As far as I can think that should work as well. I've made undefined the "sentinel object". And in your example List is undefined. So you could even do silly things like this:

module.exports = Type({Nil: [], Cons: [R.T, iAmRecursive]});

But this would not work:

var List = 'something';
List = Type({Nil: [], Cons: [R.T, List]});
Hardy Jones
@joneshf
May 18 2015 15:35
why wont that work?
Simon Friis Vindum
@paldepind
May 18 2015 16:07
@joneshf Because you're passing the string 'something' to Type in one of the fields. What's this supposed to mean:
List = Type({Nil: [], Cons: [R.T, 'something']});
Hardy Jones
@joneshf
May 18 2015 17:07
oh
Scott Christopher
@scott-christopher
May 18 2015 21:50
module.exports = Type({Nil: [], Cons: [R.T, iAmRecursive]});
will result in
ReferenceError: iAmRecursive is not defined

By declaring it first, I was suggesting:

var iAmRecursive;
module.exports = Type({Nil: [], Cons: [R.T, iAmRecursive]});

or

var iAmRecursive = module.exports = Type({Nil: [], Cons: [R.T, iAmRecursive]});