Open junosuarez opened 11 years ago
I started using it here https://gist.github.com/Raynos/b8bf27d5d05811858bfc#file-continuable-js-L10
Now sure how to make partial
more readable.
Thanks for sharing!
// partial (fn: Function, ...args: Value) => Function
// map :: (lambda:(A) => B) => (Continuable<A>) => Continuable<B>
Here, just to clarify, what is the intention of using ::
on map but not on partial? In the draft spec, the above version would annotate the named function, and the below is unspecified (although I have seen the ::
notation used elsewhere to associate a type with a function name)
// fileName := Continuable<[String]>
var fileNames = partial(fs.readdir, __dirname)
This is an interesting annotation case, which I read as a prolog-style declarative assignment. I guess I would read it as "fileName becomes a Continuable of a 1-element tuple of a string" (although in the context of fs.readdir
it looks like it would be a Continuable<Array<String>>
- see Arrays in Generic Types and Tuples - if you'd like to discuss typed-array-literal notation, please open another thread)
My question is: is it valuable to have name := type
notation distinct from name : type
? If so, can we clarify what this means semantically?
@jden I forgot to remove ::
when I ported it from Haskell style.
I also forgot to port [String]
to Array<String>
. I like the idea of having [String]
as short for Array<String>
I have used name : type
to say the name
is of this type when used as a type in either return or function arguments.
I haved name := type
to say the local variable named name
is of this type in the code.
So :
is for defining custom types. :=
is for making it obvious what the types of local variables are without having to remember what multiple applications of map
and flatten
return.
@jden another example of jsig being used https://github.com/pufuwozu/fantasy-land/issues/16#issuecomment-16326928
@jden I wouldn't mind using ::
after a function name to make things more readable.
// map (lambda:(A) => B) => (Continuable<A>) => Continuable<B>
// map :: (lambda:(A) => B) => (Continuable<A>) => Continuable<B>
I find the latter more readable because your saming the function declaration named map
has this signature. The former just uses a space seperator which is not as obvouis
@jden having thought about it more. I think having :=
:
and ::
is confusing.
Maybe just :
and :=
is enough. One declares types. The other declares signatures of values in the program. Of course the absence of either operator can still be used to mean :=
but I don't like that.
@raynos
So : is for defining custom types. := is for making it obvious what the types of local variables are without having to remember what multiple applications of map and flatten return.
I like this, it's useful for inline comments, especially in short code examples, gists, etc. Care to take a crack at writing it up in a PR?
I agree that having :
and ::
can add confusion, or at least noise. Unless there's clear value in distinguishing them, I'd rather pick one and go with it. The :
can be read as "is a", for example, "map is a function with parameters ... which returns a ..."
As currently written, the draft allows for a named function to be specified either with or without a :
. Whitespace is optional throughout.
Alternative proposal. Get rid of :
to mean "declare this name to be a certain type" :
is already overloaded in object declarations for key:value.
Instead have
// type Continuable<T> := (continuation:(err: Error, result: T) => void) => void
// map := (lambda:(A) => B) => (Continuable<A>) => Continuable<B>
The appeal of having :
at the top level is that it's just a composition of the same meaning within a type declaration (for named parameters and object properties), and that it's a symbol already in JavaScript. I'd love to get @kitcambridge's opinion here re :
vs :=
Here are some more examples from some internal code.
/*
See question.js for Question & QuestionLevelType
type SetScore := { completed: Number, correct: Number }
type Answer := {
questionId: String,
selectedAnswer: Number,
isCorrect: Boolean
}
type QuizState := {
questions: [Question],
answers: [Answer]
score: {
"Youngling": SetScore,
"Padawan": SetScore,
"Jedi Knight": SetScore,
"Jedi Master": SetScore,
"Jedi Grand Master": SetScore
},
currentSet: QuestionLevelType | "Completed"
}
*/
// QuizState := (Array<Question>) => QuizState
function QuizState(questions) {
...
}
/* see question.js for QuestionLevelType
type RangeCondition := {
type: QuestionLevelType,
is: "rangeCondition",
minimum: Number,
maximum: Number
}
type SizeCondition := {
type: QuestionLevelType,
is: "sizeCondition",
size: Number
}
type TransitionCondition := RangeCondition | SizeCondition
transitions := Object<QuestionLevelType, {
conditions: Array<TransitionCondition>,
target: QuestionLevelType,
level?: String
}>
*/
var transitions = require("../data/transitions")
// transitionSet := (QuizState, String) => QuizState
function transitionSet(quizState, completedSet) {
...
}
I like the ability to go type foo := bar | baz
. I also did is: "rangeCondition",
to say its a string and very specifically that very string.
Also note I do Object<QuestionLevelType, { ... }
where QuestionLevelType
is an Enum<String>
to say that it's an object with very specific keys and not arbitrary keys
I added an examples folder to my fork
I will also edit the README soon to update it with a bunch of changes.
I will do a search for all my docs.mli and add them to the wiki soon :)
I created a wiki page for projects using jsig - please feel free to try it out and add your own.