una teclas teclado tecla otra mueven mis lock las laptop funcionan flechas dirección desplazamiento despl como celda bloqueo bloq activar haskell arrows

teclas - Haskell: ¿Estoy malinterpretando cómo se pueden usar las flechas?



tecla bloqueo de desplazamiento o scroll lock (1)

¿Alguien puede explicar cómo entiendo mal cómo funcionan las flechas y cómo podrían usarse? ¿Hay una filosofía fundamental para las flechas que me falta?

Me da la impresión de que estás tratando a esta Arrow como si fueras una Monad . No sé si esto cuenta como una "filosofía fundamental", pero hay una diferencia significativa entre los dos, a pesar de la frecuencia con la que se superponen. En cierto sentido, la cosa clave que define una Monad es la función de join ; cómo colapsar una estructura anidada en una sola capa. Son útiles debido a lo que permite la join : puede crear nuevas capas monádicas en una función recursiva, alterar la estructura de Functor función de su contenido, etc. Pero esto no se trata de Monad s, así que lo dejaremos así.

La esencia de una Arrow , por otro lado, es una versión generalizada de una función . La clase de tipo Category define versiones generalizadas de la composición de la función y la función de identidad, mientras que la clase de tipo Arrow define cómo elevar una función regular a una Arrow y cómo trabajar con Arrow que toman múltiples argumentos (en forma de tuplas: Arrows no necesariamente puede ser curry!).

Cuando combina Arrow s de una manera básica, como en su primera función countExample , todo lo que realmente está haciendo es algo así como una composición de funciones elaborada. Mire hacia atrás a su definición de (.) está tomando dos funciones con estado y conectándolas en una sola función con estado, con el comportamiento de cambio de estado manejado automáticamente.

Por lo tanto, el principal problema con su cuenta, por countExample es que incluso las menciones count'' y tal. Todo esto se hace entre bambalinas, al igual que no es necesario pasar explícitamente el parámetro de estado cuando se usa la notación do en la mónada State .

Ahora, debido a que la notación de proceso solo le permite construir grandes Arrow compuestas, para usar realmente su función de estado, tendrá que trabajar fuera de la sintaxis de Arrow , al igual que necesita runState o runState para ejecutar un cálculo en la mónada State . Su segundo countExample es en este sentido, pero demasiado especializado. En el caso general, su función con estado asigna un flujo de entradas a un flujo de salidas, lo que lo convierte en un transductor de estado finito , por lo que runStatefulFunction probablemente tomaría una lista perezosa de valores de entrada y los convertiría en una lista perezosa de valores de salida usando un derecho pliegue con unSF para alimentar cada uno al transductor por turno.

Si desea ver un ejemplo, el paquete de arrows incluye un Automaton transformador de Arrow que define algo casi idéntico a su función de StatefulFunction , excepto con una Arrow arbitraria en lugar de la función simple que ha utilizado.

Ah, y para revisar brevemente la relación entre Arrow s y Monad s:

Las Arrows son solo cosas de función de "primer orden". Como dije antes, no siempre se pueden aplicar al curry, y de la misma manera no siempre se pueden "aplicar" en el mismo sentido en que la función ($) aplica funciones. Si realmente desea Arrows orden superior, la clase de tipo ArrowApply define una Arrow aplicación. Esto agrega una gran cantidad de poder a una Arrow y, entre otras cosas, permite la misma función de "estructura anidada de colapso" que proporciona Monad , lo que hace posible definir una instancia de ArrowApply para cualquier instancia de ArrowApply .

En la otra dirección, dado que las Monad permiten combinar funciones que crean una nueva estructura monádica, para cualquier Monad m puede hablar de una "flecha Kleisli", que es una función de tipo a -> mb . Las flechas de Kleisli para una Monad pueden recibir una instancia de Arrow de una manera bastante obvia.

Aparte de las flechas ArrowApply y Kleisli, no existe una relación particularmente interesante entre las clases de tipos.

Escribí un código de juguete para jugar con el concepto de flechas. Quería ver si podía escribir una flecha que codificara el concepto de una función con estado, dando un valor diferente después de diferentes llamadas.

{-# LANGUAGE Arrows#-} module StatefulFunc where import Control.Category import Control.Arrow newtype StatefulFunc a b = SF { unSF :: a -> (StatefulFunc a b, b) } idSF :: StatefulFunc a a idSF = SF $ /a -> (idSF, a) dotSF :: StatefulFunc b c -> StatefulFunc a b -> StatefulFunc a c dotSF f g = SF $ /a -> let (g'', b) = unSF g a (f'', c) = unSF f b in (dotSF f'' g'', c) instance Category StatefulFunc where id = idSF (.) = dotSF arrSF :: (a -> b) -> StatefulFunc a b arrSF f = ret where ret = SF fun fun a = (ret, f a) bothSF :: StatefulFunc a b -> StatefulFunc a'' b'' -> StatefulFunc (a, a'') (b, b'') bothSF f g = SF $ /(a,a'') -> let (f'', b) = unSF f a (g'', b'') = unSF g a'' in (bothSF f'' g'', (b, b'')) splitSF :: StatefulFunc a b -> StatefulFunc a b'' -> StatefulFunc a (b, b'') splitSF f g = SF $ /a -> let (f'', b) = unSF f a (g'', b'') = unSF g a in (splitSF f'' g'', (b, b'')) instance Arrow StatefulFunc where arr = arrSF first = flip bothSF idSF second = bothSF idSF (***) = bothSF (&&&) = splitSF eitherSF :: StatefulFunc a b -> StatefulFunc a'' b'' -> StatefulFunc (Either a a'') (Either b b'') eitherSF f g = SF $ /e -> case e of Left a -> let (f'', b) = unSF f a in (eitherSF f'' g, Left b) Right a'' -> let (g'', b'') = unSF g a'' in (eitherSF f g'', Right b'') mergeSF :: StatefulFunc a b -> StatefulFunc a'' b -> StatefulFunc (Either a a'') b mergeSF f g = SF $ /e -> case e of Left a -> let (f'', b) = unSF f a in (mergeSF f'' g, b) Right a'' -> let (g'', b) = unSF g a'' in (mergeSF f g'', b) instance ArrowChoice StatefulFunc where left = flip eitherSF idSF right = eitherSF idSF (+++) = eitherSF (|||) = mergeSF

Entonces, después de revisar varias definiciones de clase de tipo (no estoy seguro de si ArrowZero funcionaría para esto o no, así que lo omití), definí algunas funciones de ayuda.

evalSF :: (StatefulFunc a b) -> a -> b evalSF f a = snd (unSF f a) givenState :: s -> (s -> a -> (s, b)) -> StatefulFunc a b givenState s f = SF $ /a -> let (s'', b) = f s a in (givenState s'' f, b)

Y resuelto un ejemplo de uso.

count :: StatefulFunc a Integer count = givenState 1 $ /c _ -> (c+1, c) countExample :: StatefulFunc a Integer countExample = proc _ -> do (count'', one) <- count -< () (count'''', two) <- count'' -< () (count'''''', three) <- count'''' -< () returnA -< three

Sin embargo, cuando trato de compilar countExample , recibo los errores "No está en el alcance" para count'' y count'''' , lo que supongo que significa que debo volver al tutorial y leer qué se puede usar cuando. Creo que lo que realmente me gustaría de todos modos es algo más como

countExample :: Integer countExample = let (count'', one) = unSF count () (count'''', two) = unSF count'' () (count'''''', three) = unSF count'''' () in three

Pero eso es un poco incómodo, y esperaba algo más natural.

¿Alguien puede explicar cómo entiendo mal cómo funcionan las flechas y cómo podrían usarse? ¿Hay una filosofía fundamental para las flechas que me falta?