Как действительно 'получает' на самом деле/get/начальное состояние в Haskell?

Я также сделал это с помощью jQuery. В моем случае я хотел увидеть немного другого меню (10px). Так что это работает без Javascript (но без перехода также).

#menu li ul {
        list-style: none;
        height: 10px;
        overflow: hidden;
        margin: 0;
        padding: 0;
    }
        #menu li:hover ul {
            height: 100%;
        }

Это мой JS:

//Save the height set in css (10px)
var csshoehe = $("ul li ul").height();

// Open all the menus
$("ul li ul").css("height", "100%");

//Save each height in data-attribute
//then shrink it down again
$.each($("ul li ul"), function(){
    var hoehe = $(this).height();
    $(this).data("hoehe", hoehe);
    $(this).css("height", csshoehe);
});

$("ul li").hover(
    function(){
        var orig = $(this).children("ul").data("hoehe");
        $(this).children("ul").stop(true,false).delay(150).animate({"height": orig});
},  function(){
        $(this).children("ul").stop(true,false).delay(400).animate({"height": csshoehe});
});

Надеюсь, это кому-нибудь поможет:)

12
задан Rayne 24 June 2009 в 07:49
поделиться

3 ответа

Изначально я собирался опубликовать это в качестве комментария, но решил рассказать немного подробнее.

Строго говоря, get не «принимает» аргументы . Я думаю, что многое из того, что происходит, замаскировано тем, что вы не видите - определениями экземпляров монады State.

get на самом деле является методом класса MonadState. Монада State - это экземпляр MonadState, обеспечивающий следующее определение get :

get = State $ \s -> (s,s)

Другими словами, get просто возвращает очень простую монаду State (помня, что монада может быть рассматривается как "оболочка" для вычислений), где любой ввод s в вычисление вернет пару s в качестве результата.

Следующее, что нам нужно, посмотрите на это >> = , которое State определяет следующим образом:

m >>= k  = State $ \s -> let
    (a, s') = runState m s
    in runState (k a) s'

Итак, >> = приведет к новому вычислению, которое не будет вычисляться, пока не получит начальное состояние (это верно для всех вычислений State, когда они ' re в их «завернутом» виде). Результат этого нового вычисления достигается путем применения того, что находится справа от >> = , к результату выполнения вычисления, которое было слева. (Это довольно запутанное предложение, которое может потребовать дополнительного чтения или двух.)

Я считаю весьма полезным «десахарировать» все, что происходит. Для этого потребуется гораздо больше печатать, но ответ на ваш вопрос (откуда get ]) должен быть очень ясным. Обратите внимание, что следующий код следует рассматривать как псевдокод ...

test x =
    State $ \s -> let
        (a,s') = runState (State (\s -> (s,s))) s  --substituting above defn. of 'get'
        in runState (rightSide a) s'
        where 
          rightSide test = 
            let test' = x ++ test in
            State $ \s2 -> let
            (a2, s2') = runState (State $ \_ -> ((), test')) s2  -- defn. of 'put'
            in runState (rightSide2 a2) s2'
          rightSide2 _ =
            -- etc...

Это должно сделать очевидным, что конечный результат нашей функции - это новое вычисление Состояния, которому потребуется начальное значение ( s ), чтобы выполнить остальную работу. Вы предоставили s как "testtest" с вашим вызовом runState . Если вы замените «testtest» на s в приведенном выше псевдокоде, вы увидите, что первое, что произойдет, - это мы запустим get с «testtest» в качестве «начального состояния». Это дает («testtest», «testtest») и т. Д.

Итак, здесь get получает ваше начальное состояние «testtest». Надеюсь, это поможет!

Если вы замените «testtest» на s в приведенном выше псевдокоде, вы увидите, что первое, что произойдет, - это мы запустим get с «testtest» в качестве «начального состояния». Это дает («testtest», «testtest») и т. Д.

Итак, здесь get получает ваше начальное состояние «testtest». Надеюсь, это поможет!

Если вы замените «testtest» на s в приведенном выше псевдокоде, вы увидите, что первое, что произойдет, - это мы запустим get с «testtest» в качестве «начального состояния». Это дает («testtest», «testtest») и т. Д.

Итак, здесь get получает ваше начальное состояние «testtest». Надеюсь, это поможет!

18
ответ дан 2 December 2019 в 06:27
поделиться

Это может помочь вам глубже взглянуть на то, что на самом деле представляет собой конструктор типа State и как его использует runState. В GHCi:

Prelude Control.Monad.State> :i State
newtype State s a = State {runState :: s -> (a, s)}
Prelude Control.Monad.State> :t runState
runState :: State s a -> s -> (a, s)

State принимает два аргумента: тип состояния и возвращаемый тип. Он реализован как функция, принимающая начальное состояние и выдающая возвращаемое значение и новое состояние.

runState принимает такую ​​функцию, начальный ввод, и (наиболее вероятно) просто применяет одну к другой для получения Пара (результат, состояние).

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

В этом контексте get - это просто функция, которая принимает состояние в качестве входа и возвращает выход (результат, состояние), так что результатом является состояние входа, а состояние не изменяется (состояние выхода - состояние входа) . Другими словами, get s = (s, s)

5
ответ дан 2 December 2019 в 06:27
поделиться

Просматривая главу 8 («Функциональные синтаксические анализаторы») Грэма Хаттона Programming in Haskell несколько раз, пока я не понял ее должным образом, с последующим переходом к руководству Все о монадах , этот щелчок сделал для меня.

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

Прозрение пришло, когда я задумался. управляющие структуры в C ( для и , в то время как и т. д.), и я понял, что наиболее распространенной структурой управления было простое размещение одного оператора перед другим. Прошел год изучения Haskell, прежде чем я понял, что это даже структура управления.

1
ответ дан 2 December 2019 в 06:27
поделиться