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

Lionishy

Новичок
В Java мы можем определить абстракцию с некоторой типовой меткой T и эта метка будет строго говорить нам, что разрешается использовать только те экземпляры, для которых определена точно такая метка, то есть имена типов строго совпадают. Это именованный подход к определению типа. Очень удобен для определения типов как набора "поведений": правил преобразования, вывода экземпляров, и аксиом.

Однако такой подход не всегда удобен... Например, определять строку поведением -- избыточно. Мы просто повторим поведение списка или массива. Более простой и ясный способ определить внутреннюю структуру строки, а из неё выводить допустимое поведение. Такой подход говорит, что тип определяется своим конструктором и по существу просто псевдоним своей структуры.

Природа хранимых и обрабатываемых нами данных такова, что мы определяем возможные действия над данными, анализируя их структуру, а не только опираясь на аксиомы или правила. Это приводит к тому, что в языках типа Java, где типы могут быть только именованными, но не структурными, работа с данными осложняется. Для интуитивно одинаковых данных мы вынуждены присваивать разные метки. Мы постоянно вынуждены разводить рефлексии над типами-данными, чтобы узнать, а не сможем ли подсунуть эти данные в правильный обработчик.

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

А что в PHP?
 

Adelf

Administrator
Команда форума
Мне больше интересно было, а что там в Хаскеллах?
 
  • Like
Реакции: WMix

Lionishy

Новичок
@Adelf,
В Haskell типы, определяемые конструктором, -- структурные. То есть, псевдонимы своих конструкторов. Если определить многоразрядное число как список цифр, то все функции, доступные для списков, будут доступны для многоразрядного числа. Кроме того, можно производить "сравнение с образцом" для таких типов: то есть сравнить каким конструктором он был создан. Всё это происходит на этапе компиляции.

Поведенческие типы в Haskell отделены, называются классами типов.
Такой подход существенно повышает возможности по определению абстракций и работе с данными.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
определить внутреннюю структуру строки, а из неё выводить допустимое поведение. Такой подход говорит, что тип определяется своим конструктором
чувак, ты хоть матчасть прочти-то
https://ru.wikipedia.org/wiki/Тип_данных#.D0.9A.D0.BB.D0.B0.D1.81.D1.81.D0.B8.D1.84.D0.B8.D0.BA.D0.B0.D1.86.D0.B8.D1.8F
Структурные (агрегатные) типы не следует отождествлять со структурами данных: одни структуры данных непосредственно воплощаются определёнными структурными типами, но другие строятся посредством их композиции
структура строки - это формат, а структурный тип - это аггрегат,
определись о чем ты
 

Lionishy

Новичок
@grigori, какое отношение к описываемой проблеме имеет ваше замечание?
 
Последнее редактирование модератором:

Adelf

Administrator
Команда форума
По чесноку, я вообще не понял в чем проблема :)
Мне почемут всегда хватало мощности ООП, например языка C#. Java чутка подотстала, но не сильно уж намного. Давно хочу освоить функциональный язык какой-нибудь... пока не могу понять чем они цепляют своих фанатов
 

Lionishy

Новичок
@Adelf
В смысле абстракций функциональный язык -- это как ООП, только проще, потому что все объекты работают по одним правилам редукции.
Функциональные языки проще императивных, потому что в них явно отделяется "временная" часть от "логической", либо "временная" часть вообще отсутствует. В Haskell, например, все "нетотальные" функции (функции с побочными эффектами) компактно упаковываются. Всё это облегчает отладку.
Haskell за счёт структурного подхода к построению типов позволяет работать с небольшим количеством множеств значений, а в остальном данные и операции замкнуты, причём гораздо удобнее, чем в Java, например.

Вот и получается, что функциональные языки могут быть очень полезными.

Мне почемут всегда хватало мощности ООП
Если смотреть в корень, то ООП предлагает нам тоже, что и функциональное программирование. Только ООП сложнее, либо это не ООП...
Зато функциональные языке удобнее императивных -- это бонус!
 

Hello

Новичок
В Java мы можем определить абстракцию с некоторой типовой меткой T и эта метка будет строго говорить нам, что разрешается использовать только те экземпляры, для которых определена точно такая метка, то есть имена типов строго совпадают. Это именованный подход к определению типа. Очень удобен для определения типов как набора "поведений": правил преобразования, вывода экземпляров, и аксиом.

Однако такой подход не всегда удобен... Например, определять строку поведением -- избыточно. Мы просто повторим поведение списка или массива. Более простой и ясный способ определить внутреннюю структуру строки, а из неё выводить допустимое поведение. Такой подход говорит, что тип определяется своим конструктором и по существу просто псевдоним своей структуры.

Природа хранимых и обрабатываемых нами данных такова, что мы определяем возможные действия над данными, анализируя их структуру, а не только опираясь на аксиомы или правила. Это приводит к тому, что в языках типа Java, где типы могут быть только именованными, но не структурными, работа с данными осложняется. Для интуитивно одинаковых данных мы вынуждены присваивать разные метки. Мы постоянно вынуждены разводить рефлексии над типами-данными, чтобы узнать, а не сможем ли подсунуть эти данные в правильный обработчик.

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

А что в PHP?
А есть язык со слабой типизацией и жденериками (или как ты пишешь, типовой меткой T)?
 

Тугай

Новичок
В PHP на это наплевать, тут решают другие задачи. :)
Структурные типы в PHP - это агрегаты (User, Order, Invoice, Post, ...), которые могут быть классами или ассоциативными массивами.
Структуры данных (рекурисвные данные) список, дерево, массив, и т.п. - все это покрывается ассоциативным массивом.
Со строкой можно работать как с массивом байт, но это практически никогда не нужно. Чаще используются функции preg_* (использующие регулярные выражения).
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
@grigori, какое отношение к описываемой проблеме имеет ваше замечание?
твоя проблема, мне кажется, в незнании базовых понятий программирования, что выражается в несвязанном наборе слов,
и я предлагаю узнать значения терминов чтобы изъясняться на общем языке, быть понятым, вести конструктивный диалог

"в языках типа Java типы могут быть только именованными, но не структурными" - это бред.
Пример структурного (агрегатного) типа - массив, которые представлен одноименным типом, для списка аналогично есть List.
 

Lionishy

Новичок
узнать значения терминов
В первом сообщении всё подробно описано.
Можно для конкретного объекта анализировать прикреплённую к нему синтаксическую метку, сравнивать имена типов. Если имена равны -- то объект нужного типа.
Этот подход называется именованная система типов.

Можно для конкретного объекта сравнивать его внутреннюю структуру с внутренней структурой, с которой объявлена типовая метка.
Это подход называется структурной системой типов.

В Java система именованная.
Если объявлен класс, которой содержит внутри одно целое число и имя у него A, то объект класса B будет считаться объектом другого типа, даже если его объявить абсолютно одинаково с классом А. Использовать объект B вместо объекта A будет нельзя.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Капитан мать его за ногу очевидность :)
Если объявлена переменная int a = 20, и переменная char b = 20, то переменная b будет считаться переменной другого типа, даже если ее объявить абсолютно одинаково с переменной a. Использовать переменную b вместо переменной a нельзя, если, конечно, не хочется поэкспериментировать с segfault-ами.

а если рассматривать частный случай использования младших 8 битов из int, можно провести аналогию с реализацией классом B того же интерфейса, что и классом A, что сделает из взаимозаменяемыми
 
Последнее редактирование:

Lionishy

Новичок
К чему пример с int и char ? У них разное представление. Если бы они были взаимозаменяемыми, то это была бы негодна типизация, как в ANSI C.

Вот пример из Haskell
Код:
type Mystring = [Char]
type Charlist = [Char]
type Intlist  = [Int]

mystrlen :: Mystring -> Int
mystrlen [] = 0
mystrlen (x:xs) = 1 + (mystrlen xs)

str::Mystring
str = ['a','b','c','d','e']

bar::Charlist
bar = ['b','c','a','+','-','k','f']

foo::Intlist
foo = [1,2,3]

Функцию mystrlen можно вызвать и от str, и от bar. А от foo -- ошибка.
 

Adelf

Administrator
Команда форума
PHP:
abstract class Base{
public function t(){}
}

class A extends Base {}
class B extends Base {}
class C{}

function test(Base $t){ $t->t(); } // для пущей аргументированности можно даже убрать Base здесь и получится утиная типизация

test(new A()};
test(new B()};
test(new C()}; // а вот тут ошибка :)
 
Последнее редактирование:

Lionishy

Новичок
@Adelf, система не анализирует структуру класса A, а типовую метку Base. Это и есть именованная система типов.
Если бы можно было сделать так:
Код:
class A {
    public function hello($string);
}
class B {
    public function hello($string);
}
class C{}

function test(A $t){ $t->t(); } 

test(new A()};
test(new B()};
test(new C()}; // а вот тут ошибка :)
тогда это была бы структурная система типов.
 

Adelf

Administrator
Команда форума
Я не просто так написал коммент про утиную типизацию.
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
ООП устроен не так, как тебе бы хотелось. Здесь никто не пишет на хаскеле, хочешь - пиши. Всем пофиг.

> К чему пример с int и char ? У них разное представление.
А теперь узнай значение термина, который ты используешь: представление типов данных
У char и int представление - это цепочка битов фиксированного (кратного 8) размера. Эти типы могут различаться размером, а могут и полностью совпадать на 8-битных процессорах.
Int и char - это разные типы не потому что они представляют разные данные, а потому что у них разные цели и области применения. Полная аналогия с типами классов A и B.

Ты просто составляешь бессмысленные фразы из набора терминов, значения которых не знаешь.
 
Последнее редактирование:

Adelf

Administrator
Команда форума
Про хаскел это я попросил обьяснить. Думал там какая-то невиданная сила. Но пока тоже не понимаю о чем толкует товарищ @Lionishy.
 

Lionishy

Новичок
@grigori, И опять Вы написали что-то совершенно из другой области.

@Adelf,
Думал там какая-то невиданная сила.
Есть некоторые возможности, такие как сопоставление с образцом, которых просто нет в язык с отличными от структурной системами типов.

Например, можно объявить собственные операции ветвления:
Код:
data Mybool = T | F

if_then_else :: Mybool->t->t->t
if_then_else T t _ = t
it_then_else F _ e = e
Опираясь на структурный подход, можно проследить не столько само значение, сколько как или чем оно было создано.
Если было создано конструктором T, то возвращаем первый аргумент, если конструктором F, то второй.

Но, конечно, многие функциональные решения вполне воплотимы в рамках ООП над императивным подходом. Просто выглядят они более громоздко и при компиляции их сложнее оптимизировать.
 
Сверху