Pull to refresh

Comments 34

Тема не раскрыта. Где функциональное программирование? Где варианты из ML/хаскел, которые просто таки просятся на место enum в Си и как раз показывают изящество ФЯП, позволяющих выводить тип функции из её аргументов?
data Tea_type = Black|Green deriving Show
data Tea_cup = Tea_cup { sugar ::Bool, _type::Tea_type } deriving Show
drink :: Tea_cup -> String
drink = show

main = putStrLn $ drink $ Tea_cup True Black
ну или вот так:

data Tea_type = Black|Green|Empty deriving Show

data Tea_cup = Tea_cup { sugar ::Bool, _type::Tea_type,water::Bool } deriving Show

addTea Empty x = x
addTea t x@(Tea_cup _ Empty _) = x{ _type=t }

hasSugar = sugar
addSugar x = if hasSugar x then x else x{ sugar=True }

hasWater = water
addWater x = if hasWater x then x else x{ water=True }

newTea_cup = Tea_cup False Empty False

makeTea t = addSugar $ addTea t $ addWater $ newTea_cup

drink x@(Tea_cup _ _ False) = x

drink x = x{sugar=False, _type = Empty, water = False }

main = do
let x = makeTea Black
putStrLn $ show x
putStrLn $ show $ drink x
Чёт я не понял прикол про С++, а почему тип передаем строкой? Что за маразм? Почему бы не передать TeaCup::Type и передавать в виде TeaCup::Black, конечно может показаться, что чёрная кружка, а не чай, но можно и статические константы закинуть, в плане производительности нормальный вариант.
Действительно, хотел сделать два конструктора — один нормальный, и второй — для «ленивых» или если читаешь тип чая из конфигов. Почему-то только один, мда… Сейчас исправлю :-)
Насчёт PHP
1) Давно уже есть __autoload()
2) set_time_limit(0); было бы смешнее, если
while($cup->drink()) {} // чай можно пить бесконечно
autoload — Вы правы, изобретено давно, и технология хорошая, но не видел, чтобы его сильно активно использовали.
На мой взгляд, всякие require_once(«functions.php») еще слишком живы в среде разного рода разработчиков.
Поэтому, хоть на PHP и можно написать очень круто, с использованием современных возможностей языка, этот пример оставлю как иллюстрацию «так пишут»
// Void tea drinking
Tea::factory('black')
    ->add(array(
        'sugar' => array(
            'spoon' => 2
        ),
        'lemon' => array(
            'slice' => 1
        ),
    ))->drink();
Здорово, значительно лучше, чем сохранение объекта в переменной с последующей настройкой свойств!
Прошу прощения, это был сарказм, или мне показалось?
SQL
SELECT `content` FROM `cup` WHERE `drink` = 'black_tea' AND `content` IS NOT NULL LIMIT 1;
Скорее UNION, потому что мы же не будем выбирать из сахарницы именно тот сахар, который соответствует нашей чашке чая.
LEFT JOIN `finger` ON `finger`.`width`
Или в стиле PostgreSQL:
USING (finger)
ХабраПарсер ХабраСломался.

LEFT JOIN finger ON finger.width = cup.handler_radius
Да, тогда мой комментарий неуместен…
Тип данных sugar может не соответствовать content'у cup'а. Поэтому больше всего подходит LEFT JOIN ON 1=1 или просто SELECT FROM `cup`, `sugar`
UFO just landed and posted this here
Видимо объем описывается где-то еще и он является константой.
UFO just landed and posted this here
Видимо, давно не пил чай с сахаром, поэтому для меня это булева опция :-)
Но Вы правы, безусловно
class tea_cup:
def tea_cup(self):
self.want = []

наверное вы имели ввиду:

class tea_cup:
def __init__(self):
self.want = []

видимо привычка от C/C++
Ваш python какой-то странный. Функция tea_cup видимо по замыслу играет роль конструктора? Вот конструктор класса:

def __init__(self):
    self.want = []


И в качестве небольшого замечания: название класса не соответствует рекомендациям PEP8: TeaCup, и по хорошему, должен наследоваться от object.
Черт возьми, Вы правы :-)
Слишком увлекся остальными языками, и в Python очень косячнул, спасибо!
Из этого текста я также понял:
  • Чашки после себя моют только программисты С++ (и возможно PHP, так как реализация класса от нас скрыта)
  • Программисты на Java и С пьют чай без сахара
  • Автор всей душой ненавилит PHP, так как хуже код и придумать сложно


Мой вариант для PHP:
<?php
interface Drinkable {
	//Это можно пить
	public function drink();
}

class Liquid_Exception extends Exception {}

//Абстрактный класс Жидкость
abstract class Liquid {
	//Объем жидкости
	protected $_amount = null;

	public function setAmount($amount) {
		$this->_amount = $amount;
		return $this;
	}

	public function getAmount() {
		return $this->_amount;
	}
}

//Абстрактный класс Кипяченая жидкость
abstract class BoiledLiquid extends Liquid {
	//Уже вскипятили???
	protected $_isBoiled = false;
	
	//Уже вскипятили???
	public function isBoiled() {
		return $this->_isBoiled;
	}
	
	//Закипятить!
	public function boil() {
		$this->_isBoiled = true;
		return $this;
	}
}

//Класс Чай (наследуется от класса Кипяченая жидкость) и его можно пить!
class Tea extends BoiledLiquid implements Drinkable {
	//Количество сахара
	protected $_sugar = 0;
	//Лимончику???
	protected $_lemon = false;
	
	/*public function __construct($sugar = 0, $lemon = false) {
		$this->boil()->setSugar($sugar)->setLemon($lemon);
	}*/
	//Насыпать сахарку
	public function setSugar($sugar) {
		$this->_sugar = $sugar;
		return $this;
	}
	//Сколько сахара?
	public function getSugar() {
		return $this->_sugar;
	}
	//Кинуть лимончик
	public function setLemon($lemon) {
		$this->_lemon = $lemon;
		return $this;
	}
	//А лимончик кинули?
	public function getLemon() {
		return $this->_lemon;
	}
	
	//Пьем чай
	public function drink() {
		if ($this->getAmount() <=0 ) {
			throw new Liquid_Exception('А пить-то нечего!!!');
		}
		if (!$this->isBoiled()) {
			throw new Liquid_Exception('Пить холодный??? Фи!');
		}
		return array(
			'sugar' => $this->getSugar(),
			'lemon' => $this->getLemon()
		);
	}
}

class Cup_Exception extends Exception {}

//Абстрактный класс Чашка
abstract class Cup {
	//Вместимость чашки
	protected $_capacity = null;
	//Содержимое чашки
	protected $_liquid = null;
	
	//Наливаем в чашку жидкость
	public function fill(Liquid $liquid) {
		if ($liquid->getAmount() > $this->getCapacity()) {
			throw new Cup_Exception('Куда ты столько льешь? Кто с пола вытирать будет?');
		}
		$this->_liquid = $liquid;
		return $this;
	}

	//Выливаем жидкость из чашки
	public function outpour() {
		$liquid = $this->_liquid;
		unset($this->_liquid);
		return $liquid;
	}
	
	//Чашка пустая???
	public function isEmpty() {
		//Проверяем, что в чашке вообще содержиться жидкость и ее объем больше 0
		return (!($this->_liquid instanceOf Liquid) || $this->_liquid->getAmount() > 0);
	}

	public function setCapacity($capacity) {
		$this->_capacity = $capacity;
		return $this;
	}

	public function getCapacity() {
		return $this->_capacity;
	}
	
	public static function factory($type) {
		$className = ucfirst($type) . 'Cup';
		if (class_exists($className, true)) {
			$reflector = new ReflectionClass($className);
			//Это чашка вообще?
			if ($reflector->isSubclassOf('Cup')) {
				$args = func_get_args();
				array_shift($args);
				return ($reflector->hasMethod('__construct'))?$reflector->newInstanceArgs($args):$reflector->newInstance();
			}
		}
		return false;
	}
	
	//Магический метод для манипуляций с содержимым чашки, не выливая его
	public function __call($method, $options) {
		if (preg_match('$(set|get)Liquid(\w+)$', $method, $m)) {
			$newMethodName = $m[1].$m[2];
			if (method_exists($this->_liquid, $newMethodName)) {
				return call_user_func_array(array($this->_liquid, $newMethodName), $options);
			}
		}
		throw new Cup_Exception('Такое действие с чашкой выполнять нельзя');
	}
	
}

class CupsShelf_Exception extends Exception {}

//Коллекция чашек на полке
abstract class CupsShelf {
	//Сколько всего чашек в доме?
	protected static $_totalCupsCount = 0;
	//Все чашки, которые есть в доме
	protected static $_cups = array();
	
	public static function setTotalCupsCount($totalCupsCount) {
		self::$_totalCupsCount = $totalCupsCount;
	}

	public static function getTotalCupsCount() {
		return self::$_totalCupsCount;
	}
	
	public static function init() {
		if (self::getTotalCupsCount() > 0) {
			for($i=0;$i<=self::getTotalCupsCount();$i++){
				array_push(self::$_cups, Cup::factory('Tea')->setCapacity(0.25));
			}
		}
	}
	
	public static function getCup() {
		for($i=0;$i<=self::getTotalCupsCount();$i++){
			$cup = self::$_cups[$i];
			if ($cup->isEmpty()) {
				return $cup;
			}
		}
		throw new CupsShelf_Exception('Нет свободных чашек');
	}
}

//Класс чашка для чая
class TeaCup extends Cup {
	
}

try {
	CupsShelf::setTotalCupsCount(10);
	CupsShelf::init();
	
	//Достаем чашку с полки
	$cup = CupsShelf::getCup();
	//Завариваем чай
	$tea = new Tea();
	//И закипятить не забыли
	$tea->boil()->setAmount(0.25);
	//Наливаем в чашку
	$cup->fill($tea);
	//Кинули в чашку сахарку
	$cup->setLiquidSugar(2.5);
	//А лимончик мы не любим. Ну его!
	$cup->setLiquidLemon(false);
	//Пьем!
	$cup->outpour()->drink();
}
catch (Exception $e) {
	echo 'Да, не пить тебе чаю сегодня... (' . $e->getMessage() . ')';
}
?>

Очень развернутый комментарий!
Беглый взгляд показывает, что если убрать "$" и заменить "->" и "::" на ".", то получится неплохой пример на Java
На самом деле, Вы вселяете в меня уверенность, что на PHP программируют не только быдлокодеры.
Спасибо Вам за это :-)
Sign up to leave a comment.

Articles