Структурные и Именованные типы. Поведение или Представление?

Тугай

Новичок
Мне больше интересно было, а что там в Хаскеллах?
Топик в "лес" уходит :)
В "Хаскелах" есть типовой полиморфизм - это похоже на перегрузку методов и на полиморфизм ООП, но записывается подругому.

Вот, например :

Код:
<?php
/*
    Сортировака с использованием бинарного дерева

    Hope vs PHP
*/


/*
data tree == empty ++ leaf(num) ++ node(tree#num#tree);

dec Treesort : list(num) -> list(num);
dec MakeTree : list(num) -> tree;
dec Flatten : tree -> list(num)l;

--- MakeTree(nil) <= empty;

dec Insert : num # tree -> tree;

--- MakeTree(n::rest) <= Insert(n, MakeTree(rest));

--- Insert(n, empty) <= leaf(n);
--- Insert(n, Oldleaf & leaf(m)) <=
    if n =< m
    then node(empty, , Oldleaf)
    else node(Oldleaf, n empty);
--- Insert(n, node(left, value, right)) <=
    if n =< value
    then node(Insert(n, left), value right)
    else node(left, value, Insert(n, right));


--- Flatten(empty) <= nil;

--- Flatten(leaf(n)) <= [n];
--- Flatten(left, value, right))  <=
    Flatten(left)<>(value::Flatten(right));

let UnsortedList <= [5,2,1,9];

--- Treesort(UnsortedList) <= Flatten(MakeTree(UnsortedList));
*/


abstract class Tree
{
    public function insert($m) {}
    public function flatten() {}
}

class EmptyTree extends Tree
{
    public function insert($m)
    {
        return new LeafTree($m);
    }

    public function flatten()
    {
        return [];
    }
}

class LeafTree extends Tree
{
    public $num;

    function __construct($n)
    {
        $this->num = $n;
    }

    public function insert($m)
    {
        if ( $m > $this->num ) {
            return new NodeTree( new EmptyTree(), $this->num, new LeafTree($m) );
        } else {
            return new NodeTree( new LeafTree($m), $this->num, new EmptyTree() );
        }
    }

    public function flatten()
    {
        return [$this->num];
    }
}

class NodeTree extends Tree
{
    public $leftTree;
    public $num;
    public $rightTree;

    function __construct($lt, $n, $rt)
    {
        $this->leftTree = $lt;
        $this->num = $n;
        $this->rightTree = $rt;
    }

    public function insert($m)
    {
        if ( $m > $this->num ) {
            $this->rightTree = $this->rightTree->insert($m);
        } else {
            $this->leftTree = $this->leftTree->insert($m);
        }
        return $this;
    }

    public function flatten()
    {
        return array_merge( $this->leftTree->flatten(), [$this->num], $this->rightTree->flatten() );
    }
}


function makeTree($list)
{
    /*
    $tree = new EmptyTree();

    foreach($list as $l) {
        $tree =    $tree->insert($l);
    }

    return $tree;
    */

    return array_reduce($list, function ($t, $l) { return $t->insert($l); }, new EmptyTree());
}


print_r(makeTree([5,2,1,9])->flatten()); // [1,2,5,9]
В функциональных языках, есть инструкции типа "data tree == empty ++ leaf(num) ++ node(tree#num#tree);", тип tree тут тройственный и по-этому "dec Insert : num # tree -> tree;" - фактически описание для 3 функций.
 
Последнее редактирование:

Тугай

Новичок
В случае с функцией act логический анализ выглядел бы так: функция принимает тип T, который есть сумма из трёх типов G | C | F. Если в функцию act поступает тип P, то мы получим ошибку компиляции. Если в функцию поступает тип C, то набор альтернатив, определённых в функции act, заменяется на конкретную альтернативу для метки C.
...
P.P.S. В рамках принятой в Java системы типов повторить это просто невозможно. Это как пытаться пересилить постулат о параллельных прямых.
...
Пересилил или нет на PHP, в примере про сортировку ? Там бинарное дерево как раз и есть сумма трех типов. В роли act функции insert и flatten.
По-моему это просто полиморфизм ООП.
 

Lionishy

Новичок
@Тугай,
PHP:
class ErrorTree extends Tree {
    public function insert($m) {}
    public function flatten() {}
}
Если выражать словами, то Tree -- это не тип, в смысле конструирования значений, а тип, в смысле поведения, то есть целый класс типов.

И я могу создать бесконечно много экземпляров класса Tree, параметризованных другими типами:
PHP:
class NewTree extends Tree implements TG, TH {
}
 
Последнее редактирование:

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Вы нашли друг друга :)

Краткий ликбез. Инвариант — это утверждение, которое будет для объекта справедливо всегда. И в данном случае инвариант звучит как «значение enum всегда будет принадлежать фиксированному множеству E».
Спасибо. Я хотел написать, что вопрос получается в терминологии. Если составить enum из классов, то получится конечный набор инвариантов.
Но мне реально надоела эта мастурбация.

Это не имеет отношения к ООП. Объект должен контролировать собственные инварианты сам. Иначе ты придешь к той же anemic domain model, когда «модель» вообще ничего о себе не контролирует, а всё делегирует каким-то «сервисам». Это процедурное программирование.

Это примерно как считать, что вместо DateTime надо иметь анемичный DateTime + DateTimeFactory. А ты попробуй написать new DateTime('trash'), будет ли поведение молчаливым, каким его хочешь видеть ты.
это вопрос уровня абстракции. date_create() можно считать фабрикой,
а молчаливость - я вообще не понимаю о чем ты, я говорю что исключения нужны
 
Последнее редактирование:

Вурдалак

Продвинутый новичок
это вопрос уровня абстракции. date_create() можно считать фабрикой,
а молчаливость - я вообще не понимаю о чем ты, я говорю что исключения нужны
Согласно мануалу, date_create() — это алиас (абсолютно бессмысленный, на мой взгляд) к DateTime::__construct(). Т.е. если ты за исключения в конструкторе, то тогда, конечно, ты говоришь абсолютно про то же самое, что и я.

Не нужно позволять создавать бессмысленные объекты. Для этой цели и нужны проверки в конструкторе. Это абсолютно естественное положение вещей.
Я не вижу смысла для этой цели использовать фабрики: это усложнение (фабрики нужны редко, для value object скорее никогда) и это не является решением (но я могу допустить, что фабрика может быть удобна в тех языках, где есть приватные классы).
 

fixxxer

К.О.
Партнер клуба
но я могу допустить, что фабрика может быть удобна в тех языках, где есть приватные классы
Кстати, да. Вот немного пишу на TypeScript с ES6 модулями. Явный экспорт и приватные классы заметно влияют на дизайн
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Согласно мануалу, date_create() — это алиас (абсолютно бессмысленный, на мой взгляд) к DateTime::__construct(). Т.е. если ты за исключения в конструкторе, то тогда, конечно, ты говоришь абсолютно про то же самое, что и я.
Мануал врет, начиная с 5.3 это не алиас именно в способе обработки ошибок, и это документировано.

$ php -r 'var_dump(date_create("shit"));'
bool(false)
$ php -r 'var_dump(new DateTime("shit"));'

Fatal error: Uncaught exception 'Exception' with message 'DateTime::__construct(): Failed to parse time string (shit) at position 0 (s): The timezone could not be found in the database' in Command line code:1
Stack trace:
#0 Command line code(1): DateTime->__construct('shit')
#1 {main}
thrown in Command line code on line 1
поэтому можно написать if($DateTime = date_create($date_string)){...
 
Последнее редактирование:
Сверху