Haskell: Am I misunderstanding how Arrows may be used?

半腔热情 提交于 2019-11-29 22:24:20

Can anyone explain how I'm misunderstanding how Arrows work, and how they might be used? Is there fundamental philosophy to Arrows that I'm missing?

I get the impression that you're treating this Arrow like you would a Monad. I don't know if this counts as a "fundamental philosophy", but there's a significant difference between the two, despite how often they overlap. In a sense the key thing that defines a Monad is the join function; how to collapse a nested structure into a single layer. They're useful because of what join allows: you can create new monadic layers in a recursive function, alter the Functor structure based on its contents, and so on. But this isn't about Monads, so we'll leave it at that.

The essence of an Arrow, on the other hand, is a generalized version of a function. The Category type class defines generalized versions of function composition and the identity function, while the Arrow type class defines how to lift a regular function to an Arrow and how to work with Arrows that take multiple arguments (in the form of tuples--Arrows can't necessarily be curried!).

When combining Arrows in a basic manner, as in your first countExample function, all you're really doing is something like elaborate function composition. Look back at your definition of (.)--you're taking two stateful functions and connecting them into a single stateful function, with the state change behavior handled automatically.

So, the main problem with your countExample is that it even mentions count' and such. That's all done behind the scenes, just like you don't need to explicitly pass the state parameter along when using do notation in the State monad.

Now, because the proc notation just lets you construct large composite Arrows, to actually use your stateful function you'll need to work outside the Arrow syntax, just like you need runState or such in order to actually run a computation in the State monad. Your second countExample is along these lines, but too specialized. In the general case, your stateful function maps a stream of inputs to a stream of outputs, making it a finite state transducer, so runStatefulFunction would probably take a lazy list of input values and convert them into a lazy list of output values using a right fold with unSF to feed each to the transducer in turn.

If you'd like to see an example, the arrows package includes an Arrow transformer Automaton that defines something almost identical to your StatefulFunction, except with an arbitrary Arrow in place of the plain function you've used.


Oh, and to briefly revisit the relationship between Arrows and Monads:

Plain Arrows are only "first-order" function-like things. As I said before, they can't always be curried, and likewise they can't always be "applied" in the same sense that the ($) function applies functions. If you do actually want higher-order Arrows, the type class ArrowApply defines an application Arrow. This adds a great deal of power to an Arrow and, among other things, allows the same "collapse nested structure" feature that Monad provides, making it possible to define generally a Monad instance for any ArrowApply instance.

In the other direction, because Monads allow combining functions that create new monadic structure, for any Monad m you can talk about a "Kleisli arrow", which is a function of type a -> m b. Kleisli arrows for a Monad can be given an Arrow instance in a pretty obvious way.

Other than ArrowApply and Kleisli arrows, there's no particularly interesting relationship between the type classes.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!