У меня есть только теоретическое представление о типах сумм Haskell. И все же я чувствую, что они действительно важны в Haskell и коренным образом меняют способ моделирования ваших данных. Поскольку я считаю, что они могут быть полезны и в языках с динамической типизацией, я попытался реализовать разумное приближение в Javascript (у меня лишь поверхностное знание Haskell).
Вот более или менее полезный пример типа суммы Name
, который может обрабатывать различные форматы имен. Я знаю, что Haskell различает конструкторы типов и конструкторы данных и, вероятно, имеет веские причины для такого различия. Однако я предполагаю, что невозможно сопоставить эту концепцию с Javascript. И ни одно из них не соответствует образцу.
Во всяком случае, мой фактический вопрос: воплощает ли следующая реализация природу типов сумм и то, как они применяются в Haskell?
Обратите внимание: я не уверен, что такие межъязыковые вопросы приветствуются на SO. Пожалуйста, дайте мне знать, если я должен избегать их.
// auxiliary functions
const A = f => x => f(x);
const show = api => api.show;
// the type constructor
const Name = (...xs) => A(({length: len}) => {
switch (len) {
case 1: {
let [{length: len}] = xs; // no pattern matching but destructuring
if (len > 1) { // no Char type in JS
return k => k({show: () => xs[0]}); // returns the API
}
break;
}
case 2: {
let [{length: len}, {length: len2}] = xs;
if (len > 1 && len2 > 1) {
return k => k({show: () => `${xs[0]} ${xs[1]}`});
}
if (len === 1 && len2 > 1) {
return k => k({show: () => `${xs[0]}. ${xs[1]}`});
}
break;
}
case 3: {
let [{length: len}, {length: len2}, {length: len3}] = xs;
if (len > 1 && len2 > 1 && len3 > 1) {
return k => k({show: () => `${xs[0]} ${xs[1]} ${xs[2]}`});
}
if (len > 1 && len2 === 1 && len3 > 1) {
return k => k({show: () => `${xs[0]} ${xs[1]}. ${xs[2]}`});
}
if (len === 1 && len2 === 1 && len3 > 1) {
return k => k({show: () => `${xs[0]}. ${xs[1]}. ${xs[2]}`});
}
}
default: throw new TypeError();
}
}) (xs);
// run
console.log(Name("Kerouac") (show) ());
console.log(Name("Hans", "Hölzel") (show) ());
console.log(Name("H", "Curry") (show) ());
console.log(Name("Jean", "Luc", "Godard") (show) ());
console.log(Name("William", "S", "Burroughs") (show) ());
console.log(Name("E", "W", "Dijkstra") (show) ());
[ИЗМЕНИТЬ]
Извините, я должен был предоставить код на Haskell:
type FirstName = String
type LastName = String
type MiddleName = String
data Name = FullName FirstName LastName
| NameWithMiddle FirstName MiddleName LastName
| NameWithMiddleInitial FirstName Char LastName
| TwoInitialsWithLast Char Char LastName
| OneInitialWithLast Char LastName
| LastNameOnly LastName
Хотя я не уверен, что это действительно так.
Я предполагаю, что проблема с моим подходом заключается в том, что я пытаюсь реализовать конструктор типа Name
, в то время как я должен реализовать конструкторы значений, верно?
Either Char String
, но его гораздо проще написать как(Bool, String)
, особенно в JS. Хотя я вижу, что «технически» это тип суммы, в Haskell он не используется таким образом (особенно при встраивании интеллектуальных конструкторов в тип). - person user2407038   schedule 06.03.2017switch
выглядит так, как будто вы удачно успешно сопоставили концепцию сопоставления с образцом с JS. - person Bergi   schedule 06.03.2017daggy
? Он использует своего рода кодирование Черча с некоторыми синтаксическими тонкостями. - person phipsgabler   schedule 06.03.2017