Может ли это быть реорганизовано для использования общих функциональных принципов?
Функция компаратора ascending
принимает два аргумента - a
а также b
, Он должен вернуть целое число, сравнивая два.
У меня есть список, который я хочу отсортировать по имени, поэтому я написал следующие функции.
Есть ли функциональная идиома, которую я могу использовать, чтобы объединить эти две функции, вместо того, чтобы byName
взять на себя ответственность за составление результирующей функции?
const ascending = (a, b) => a.localeCompare(b);
const byName = (i) => i.get('name');
const useTogether = (...fns) => ...; // is there an idiomatic function like this?
// usage
items.sort(useTogether(byName(ascending)));
2 ответа
Я не уверен, удовлетворяет ли это тому, что вы ищете, но вот одна из возможных формулировок вашего useTogether
(с несколько другой подписью), который работает. Мне не известна стандартная функция с именно таким эффектом.
const ascending = (a, b) => a.localeCompare(b);
const byName = (i) => i['name'];
const useTogether = (selector, consumer) => (...fnArgs) => consumer(...fnArgs.map(selector));
var items = [{ name: "C" }, { name: "A" }, { name: "B" }];
console.log(
items.sort(useTogether(byName, ascending))
)
Вы ищете контравариантные функторы
Чтобы оценить их должным образом, давайте начнем с изучения самой основной программы сортировки
const compare = (a, b) =>
a.localeCompare (b)
const data =
[ 'Cindy'
, 'Alice'
, 'Darius'
, 'Bertrand'
]
data.sort (compare)
console.log (data)
// Alice, Bertrand, Cindy, Darius
Ничего особенного там нет. Давайте сделаем наш первый контравариантный функтор, Comparison
, Сортировка вызывает мутации, но все равно для демонстрации. Сконцентрируйся contramap
const compare = (a, b) =>
a.localeCompare (b)
const Comparison = (f = compare) =>
({ contramap : g =>
Comparison ((a, b) => f (g (a), g (b)))
, sort : xs =>
xs.sort (f)
})
const data =
[ { name: 'Cindy' }
, { name: 'Alice' }
, { name: 'Darius' }
, { name: 'Bertrand' }
]
Comparison ()
.contramap (x => x.name)
.sort (data)
console.log (data)
// Alice, Bertrand, Cindy, Darius
Состав закона имеет место
m.contramap(f).contramap(g) == m.contramap(compose(f,g))
const compare = (a, b) =>
a.localeCompare (b)
const Comparison = (f = compare) =>
({ contramap : g =>
Comparison ((a, b) => f (g (a), g (b)))
, sort : xs =>
xs.sort (f)
})
const data =
[ { name: 'Cindy' }
, { name: 'Alice' }
, { name: 'Darius' }
, { name: 'Bertrand' }
]
const compose = (f, g) =>
x => f (g (x))
Comparison ()
.contramap (compose (x => x.substr (1), x => x.name))
// equivalent to
// .contramap (x => x.substr (1)) // sort starting with second letter
// .contramap (x => x.name) // get name property
.sort (data)
console.log (data)
// sorted by second letter this time (A, E, I, L)
// Darius, Bertrand, Cindy, Alice
// ^ ^ ^ ^
Реализация моноидного интерфейса дает вам классные вещи, такие как "мультисортировка"
const Eq =
0
const Lt =
-1
const Gt =
1
const Ord =
{ empty: Eq
, concat: (a,b) =>
a === Eq ? b : a
}
const compare = (a, b) =>
a < b ? Lt
: a > b ? Gt
: Eq
const Comparison = (f = compare) =>
({ compare: f
, contramap : g =>
Comparison ((a, b) => f (g (a), g (b)))
, concat : m =>
Comparison ((a, b) =>
Ord.concat (f (a, b), m.compare (a, b)))
, sort : xs =>
xs.sort (f)
})
const data =
[ { name: 'Alicia', age: 10 }
, { name: 'Alice', age: 15 }
, { name: 'Alice', age: 10 }
, { name: 'Alice', age: 16 }
]
const sortByName =
Comparison ()
.contramap (x => x.name)
const sortByAge =
Comparison ()
.contramap (x => x.age)
sortByName
.concat (sortByAge)
.sort (data)
console.log ('sorted by (name,age)', data)
// Alice 10
// Alice 15
// Alice 16
// Alicia 10
sortByAge
.concat (sortByName)
.sort (data)
console.log ('sorted by (age,name)', data)
// Alice 10
// Alicia 10
// Alice 15
// Alice 16
Прочитайте связанную статью для более полезной информации и введения в датчики