Сейчас это не поддерживается. Flutter Studio не выглядит стабильно и содержит ошибки. Таким образом, до сих пор единственным предпочтительным способом является использование Hot Reload . Если вы хотите отладить проблемы, связанные с макетом, вы можете сделать следующее:
main.dart
) import 'package:flutter/rendering.dart';
[1114 ]
main()
, добавьте эти строки, чтобы включить отладку макета перед методом runApp()
: debugPaintSizeEnabled = true;
debugPaintBaselinesEnabled = true;
[1116 ]
debugPaintPointersEnabled = true;
Я бы сказал, что состояние в целом не является запахом кода, если оно остается небольшим и хорошо контролируется.
Это означает, что использование таких монад, как State, ST или созданные на заказ, или просто наличие структуры данных, содержащей данные о состоянии, которые вы передаете в несколько мест, - это неплохо. (На самом деле, монады просто помогают в этом!) Однако наличие состояния, которое распространяется повсюду (да, это означает, что вы, монада ввода-вывода!) - неприятный запах.
Достаточно наглядным примером этого является то, что моя команда работала над нашей записью на ICFP Programming Contest 2009 (код доступен на git : //git.cynic.net/haskell/icfp-contest-2009). В итоге мы получили несколько различных модульных частей:
Каждый из них имеет собственное состояние, и все они по-разному взаимодействуют через входные и выходные значения виртуальной машины. У нас было несколько разных контроллеров и визуализаторов, каждый из которых имел свой собственный тип состояния.
Ключевым моментом здесь было то, что внутренние компоненты любого конкретного состояния были ограничены своими собственными конкретными модулями, и каждый модуль ничего не знал даже о наличие состояния для других модулей. Любой конкретный набор кода и данных с отслеживанием состояния обычно состоял из нескольких десятков строк с несколькими элементами данных в состоянии.
Все это было склеено в одну небольшую функцию из примерно десятка строк, которые не имели доступа к внутренности любого из состояний, которые просто вызывали нужные вещи в правильном порядке, когда он проходил через симуляцию, и передавали очень ограниченное количество внешней информации каждому модулю (вместе с модулем ' s предыдущее состояние, конечно).
Когда состояние используется таким ограниченным образом, а система типов не дает вам случайно изменить его, с этим довольно легко справиться. Одно из преимуществ Haskell - то, что он позволяет вам это делать.
Один из ответов гласит: «Не используйте монады». С моей точки зрения, это как раз наоборот. Монады - это управляющая структура, которая, помимо прочего, может помочь вам минимизировать объем кода, который касается состояния. Если вы посмотрите на монадические синтаксические анализаторы в качестве примера, состояние синтаксического анализа (т. Е. Анализируемый текст, расстояние до него, любые накопленные предупреждения и т. Д.) Должно проходить через каждый комбинатор, используемый в синтаксическом анализаторе. . Тем не менее, будет только несколько комбинаторов, которые непосредственно управляют состоянием; все остальное использует одну из этих немногих функций.
Я записал несколько компиляторов в Haskell, и монада состояния является разумным решением многих проблем компилятора. Но Вы хотите сохранить это, краткий обзор---не делает это очевидным, что Вы используете монаду.
Вот пример из Компилятора Haskell Глазго (который я сделал не запись; я просто работаю вокруг нескольких краев), где мы создаем графики потока управления. Вот основные способы сделать графики:
empyGraph :: Graph
mkLabel :: Label -> Graph
mkAssignment :: Assignment -> Graph -- modify a register or memory
mkTransfer :: ControlTransfer -> Graph -- any control transfer
(<*>) :: Graph -> Graph -> Graph
, Но поскольку Вы обнаружили, поддержав предоставление уникальных маркировок, утомительно в лучшем случае таким образом, мы обеспечиваем эти функции также:
withFreshLabel :: (Label -> Graph) -> Graph
mkIfThenElse :: (Label -> Label -> Graph) -- branch condition
-> Graph -- code in the 'then' branch
-> Graph -- code in the 'else' branch
-> Graph -- resulting if-then-else construct
целое Graph
вещью является абстрактный тип, и переводчик просто весело создает графики чисто функциональным способом, не будучи знающим, что что-либо одноместное продолжается. Затем когда график наконец создается для превращения его в алгебраический тип данных, от которого мы можем сгенерировать код, мы даем ему предоставление уникальных маркировок, выполняем монаду состояния и вытаскиваем структуру данных.
монада состояния скрыта внизу; хотя это не представлено клиенту, определение Graph
является чем-то вроде этого:
type Graph = RealGraph -> [Label] -> (RealGraph, [Label])
или немного более точно
type Graph = RealGraph -> State [Label] RealGraph
-- a Graph is a monadic function from a successor RealGraph to a new RealGraph
С монадой состояния, скрытой позади слоя абстракции, это не является вонючим вообще!
Вы посмотрели Атрибутные грамматики (AG)? (Больше информации о Википедия и статья в Читателе Монады)?
С AG можно добавить атрибуты к синтаксическому дереву. Эти атрибуты разделяются в , синтезировал , и наследовался атрибуты.
Синтезируемые атрибуты являются вещами, которые Вы генерируете (или синтезируйте) от Вашего синтаксического дерева это могло быть сгенерированным кодом или всеми комментариями, или безотносительно Вашего заинтересованного.
Наследованные атрибуты вводятся к Вашему синтаксическому дереву, это могло быть средой или списком маркировок для использования во время генерации кода.
В Утрехтском университете мы используем Система Атрибутной грамматики ( UUAGC) для записи компиляторов. Это - препроцессор, который генерирует haskell код (.hs
файлы) от обеспеченного .ag
файлы.
, Хотя, если Вы все еще изучаете Haskell, тогда возможно, это не время, чтобы начать изучать еще один слой абстракции по этому.
В этом случае, Вы могли вручную записать вид кода, который грамматики атрибутов генерируют для Вас, например:
data AbstractSyntax = Literal Int | Block AbstractSyntax
| Comment String AbstractSyntax
compile :: AbstractSyntax -> [Label] -> (Code, Comments)
compile (Literal x) _ = (generateCode x, [])
compile (Block ast) (l:ls) = let (code', comments) = compile ast ls
in (labelCode l code', comments)
compile (Comment s ast) ls = let (code, comments') = compile ast ls
in (code, s : comments')
generateCode :: Int -> Code
labelCode :: Label -> Code -> Code
Возможно, что можно хотеть применимый функтор вместо монады:
http://www.haskell.org/haskellwiki/Applicative_functor
я думаю, что исходная бумага объясняет это лучше, чем Wiki, однако:
В целом необходимо стараться избегать состояния по мере возможности, но это не всегда практично. Applicative
заставляет код effectful выглядеть более хорошим, и более функциональный код особенно обхода дерева может извлечь выгоду из этого стиля. Для проблемы поколения имени существует теперь довольно хороший доступный пакет: предоставление значения .
Ну, не используйте монады. Питание функционального программирования является функциональной чистотой и их повторным использованием. Существует данная статья, которую однажды записал мой преподаватель, и он - один из парней, которые помогли создать Haskell.
бумагу называют" , Почему функциональное программирование имеет значение ", я предполагаю, что Вы прочитываете его. Это - хорошее чтение.
давайте будем осторожны относительно терминологии здесь. Состояние не по сути плохо; функциональные языки имеют состояние. То, что является "запахом кода", когда Вы желаете, чтобы присвоить значения переменных и изменить их.
, Конечно, монада состояния Haskell там для просто, что причина - как с вводом-выводом, она позволяет Вам сделать небезопасные и нефункциональные вещи в ограниченном контексте.
Так, да, это - вероятно, запах кода.