Сопоставление Шаблонов Java 8?
будет ли Java 8 поддерживать сопоставление шаблонов, как Scala и другие функциональные программы? Я собираю презентацию функций лямбда Java 8. Я не могу найти ничего об этой конкретной концепции функционального программирования.
Я помню, что меня заинтересовало функциональное программирование, это реализация quicksort, особенно по сравнению с реализацией императивного программирования.
4 ответов
Я полагаю, вы говорите не о сопоставлении шаблонов в смысле применения регулярного выражения к строке, а как применяется в Haskell. Например, используя подстановочные знаки:
head (x:_) = x
tail (_:xs) = xs
Java 8 не будет поддерживать Это изначально, с лямбда-выражением есть, однако, способы сделать это, например, для вычисления факториала:
public static int fact(int n) {
return ((Integer) new PatternMatching(
inCaseOf(0, _ -> 1),
otherwise( _ -> n * fact(n - 1))
).matchFor(n));
}
Как реализовать это вы найдете более подробную информацию в этом блоге:к шаблону в Java.
можно реализовать сопоставление шаблонов в качестве библиотеки в Java 8 (используя лямбда-выражения), но, к сожалению, нам все равно будет не хватать проверки полноты компилятора, которую имеют такие языки, как Haskell или Scala.
Циклоп-реагировать мощный Шаблоны модуль, который предлагает как структурное сопоставление шаблонов для Java 8, так и сопоставление шаблонов через guards.
он обеспечивает когда / тогда / в противном случае DSL и matching, включая деконструкцию, основаны на стандартных предикатах Java (поэтому matching можно использовать для фильтрации потока, например).
соответствующие охранниками
для сопоставления с помощью охранников мы используем whenGuard / then / в противном случае, чтобы четко показать, что случай ведет тест, а не структуру тестируемого объекта.
например, для сопоставления на основе guard, если мы реализуем класс Case, который реализует сопоставимый интерфейс
static class MyCase implements Matchable{ int a; int b; int c;}
(кстати, Ломбок может очень пригодиться для создания иерархий запечатанных классов)
мы можем соответствовать его внутренним значениям (рекурсивно, если необходимо, или по типу среди различных других опций).
import static com.aol.cyclops.control.Matchable.otherwise;
import static com.aol.cyclops.control.Matchable.whenGuard;
new MyCase(1,2,3).matches(c->c.is(whenGuard(1,2,3)).then("hello"),
.is(whenGuard(4,5,6)).then("goodbye")
,otherwise("goodbye")
);
если у нас есть объект, который не реализует [Matchable] [3], мы можем принудить его к Matchable в любом случае, наш код станет
Matchable.ofDecomposable(()->new MyCase(1,2,3)))
.matches(c->c.is(whenGuard(1,2,3)).then("hello"),
.is(whenGuard(4,5,6)).then("goodbye")
,otherwise("hello"));
если мы не заботимся об одном из значений, мы можем использовать подстановочные знаки
new MyCase(1,2,3).matches(c->c.is(whenGuard(1,__,3)).then("hello"),
.is(whenGuard(4,__,6)).then("goodbye")
,otherwise("hello)
);
или рекурсивно деструктурировать вложенный набор классов
Matchable.of(new NestedCase(1,2,new NestedCase(3,4,null)))
.matches(c->c.is(whenGuard(1,__,has(3,4,__)).then("2")
,otherwise("default");
где NestedCase выглядит примерно так -
class NestedCase implemends Decomposable { int a; int b; NestedCase c; }
пользователи также могут создавать выражения соответствия шаблону с помощью hamcrest
import static com.aol.cyclops.control.Matchable.otherwise;
import static com.aol.cyclops.control.Matchable.then;
import static com.aol.cyclops.control.Matchable.when;
Matchable.of(Arrays.asList(1,2,3))
.matches(c->c.is(when(equalTo(1),any(Integer.class),equalTo(4)))
.then("2"),otherwise("default"));
структурный шаблон соответствия
мы также можем сопоставить точную структуру тестируемого объекта. Это вместо того, чтобы использовать тесты if / then, чтобы увидеть, соответствует ли структура нашим случаям, мы можем иметь компилятор гарантирует, что наши случаи соответствуют структуре предоставленных объектов. DSL для этого почти идентичен в соответствии с guard based matching, но мы используем when / then / otherwise, чтобы четко показать структуру объектов, приводящих тестовые случаи, а не наоборот.
import static com.aol.cyclops.control.Matchable.otherwise;
import static com.aol.cyclops.control.Matchable.then;
import static com.aol.cyclops.control.Matchable.when;
String result = new Customer("test",new Address(10,"hello","my city"))
.match()
.on$_2()
.matches(c->c.is(when(decons(when(10,"hello","my city"))),then("hello")), otherwise("miss")).get();
//"hello"
структурное сопоставление объекта адреса, извлеченного из клиента. Где клиент и адрес классы выглядят это это
@AllArgsConstructor
static class Address{
int house;
String street;
String city;
public MTuple3<Integer,String,String> match(){
return Matchable.from(()->house,()->street,()->city);
}
}
@AllArgsConstructor
static class Customer{
String name;
Address address;
public MTuple2<String,MTuple3<Integer,String,String>> match(){
return Matchable.from(()->name,()->Maybe.ofNullable(address).map(a->a.match()).orElseGet(()->null));
}
}
cyclops-react обеспечивает Matchables класс, который позволяет сопоставлять структурный шаблон с общими типами JDK.
Derive4J - это библиотека, направленная на поддержку почти родной поддержки типов сумм и структурного сопоставления шаблонов для java (и даже больше). Взяв в качестве примера небольшой калькулятор DSL, с помощью Derive4J вы можете написать следующий код:
import java.util.function.Function;
import org.derive4j.Data;
import static org.derive4j.exemple.Expressions.*;
@Data
public abstract class Expression {
interface Cases<R> {
R Const(Integer value);
R Add(Expression left, Expression right);
R Mult(Expression left, Expression right);
R Neg(Expression expr);
}
public abstract <R> R match(Cases<R> cases);
private static Function<Expression, Integer> eval = Expressions
.match()
.Const(value -> value)
.Add((left, right) -> eval(left) + eval(right))
.Mult((left, right) -> eval(left) * eval(right))
.Neg(expr -> -eval(expr));
public static Integer eval(Expression expression) {
return eval.apply(expression);
}
public static void main(String[] args) {
Expression expr = Add(Const(1), Mult(Const(2), Mult(Const(3), Const(3))));
System.out.println(eval(expr)); // (1+(2*(3*3))) = 19
}
}
Я знаю, что на этот вопрос уже дан ответ, кроме того, я новичок в функциональном программировании, но, после долгих колебаний, я, наконец, решил получить invloved в этом обсуждении, чтобы иметь обратную связь о том, что следует.
Я бы предложил (слишком ?) простая реализация ниже. Он немного отличается от (хорошей) статьи, приведенной в принятом ответе ; но в моем (коротком) опыте он был немного более гибким в использовании и простым в обслуживании (что, конечно, также дело вкуса.)
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
final class Test
{
public static final Function<Integer, Integer> fact = new Match<Integer>()
.caseOf( i -> i == 0, i -> 1 )
.otherwise( i -> i * Test.fact.apply(i - 1) );
public static final Function<Object, String> dummy = new Match<Object>()
.caseOf( i -> i.equals(42), i -> "forty-two" )
.caseOf( i -> i instanceof Integer, i -> "Integer : " + i.toString() )
.caseOf( i -> i.equals("world"), i -> "Hello " + i.toString() )
.otherwise( i -> "got this : " + i.toString() );
public static void main(String[] args)
{
System.out.println("factorial : " + fact.apply(6));
System.out.println("dummy : " + dummy.apply(42));
System.out.println("dummy : " + dummy.apply(6));
System.out.println("dummy : " + dummy.apply("world"));
System.out.println("dummy : " + dummy.apply("does not match"));
}
}
final class Match<T>
{
public <U> CaseOf<U> caseOf(Predicate<T> cond, Function<T, U> map)
{
return this.new CaseOf<U>(cond, map, Optional.empty());
}
class CaseOf<U> implements Function<T, Optional<U>>
{
private Predicate<T> cond;
private Function<T, U> map;
private Optional<CaseOf<U>> previous;
CaseOf(Predicate<T> cond, Function<T, U> map, Optional<CaseOf<U>> previous)
{
this.cond = cond;
this.map = map;
this.previous = previous;
}
@Override
public Optional<U> apply(T value)
{
Optional<U> r = previous.flatMap( p -> p.apply(value) );
return r.isPresent() || !cond.test(value) ? r
: Optional.of( this.map.apply(value) );
}
public CaseOf<U> caseOf(Predicate<T> cond, Function<T, U> map)
{
return new CaseOf<U>(cond, map, Optional.of(this));
}
public Function<T,U> otherwise(Function<T, U> map)
{
return value -> this.apply(value)
.orElseGet( () -> map.apply(value) );
}
}
}