问题
I have a tuple of values representing some state, and want to translate it by an addition (shift). My values are a longer version of ( Int, [Int], Int), and I want something conceptually (but not literally) like this:
shift n = ??? (+n) (id, map, id) -- simple(?)
which would be equivalent to:
shift n (a, b, c) = (a+n, map (+n) b, c+n)
I am happy to just go with this explicit function usage, but wondered it there was a more idiomatic point-free version using Applicative or Arrows or ..., or if they would just end-up obfuscating things. I thought that the point-free version shows the basic structure of the operation more clearly.
回答1:
With the DeriveFunctor
language extension you can write
data MyState a = MyState a [a] a
deriving (Functor)
The derived instance looks like
instance Functor MyState where
fmap f (MyState a bs c) = MyState (f a) (map f bs) (f c)
Now you can define
shift :: MyState Int -> MyState Int
shift n = fmap (+n)
(You say your tuple is even longer than (Int, [Int], Int)
, so you may want to define your state type using record syntax.)
回答2:
You can just write
shift n (a,b,c) = (a+n, map (+n) b, c+n)
Or define new combinators similar to Arrow's (***)
and (&&&)
,
prod3 (f,g,h) (a,b,c) = (f a, g b, h c) -- cf. (***)
call3 (f,g,h) x = (f x, g x, h x) -- cf. (&&&)
ap3 f (a,b,c) = (f a, f b, f c)
uncurry3 f (a,b,c) = f a b c
and then call
prod3 ( (+n), map (+n), (+n) ) (a,b,c)
or even (with appropriately set operator precedences)
ap3 ($ (+n)) (id, map, id) `prod3` (a,b,c)
Or, if you'd write your triples as nested pairs, you could use
Prelude Control.Arrow> ( (+5) *** map (+5) *** (+5) ) (1,([2,3],4))
(6,([7,8],9))
So for nested pairs,
shift' :: (Num b) => b -> (b, ([b], b)) -> (b, ([b], b))
shift' n = ( (+n) *** map (+n) *** (+n) )
(see also Multiple folds in one pass using generic tuple function)
回答3:
Applying a list of functions to a list of values is simply
zipWith ($)
Since tuples of different sizes are each their own type, you will have to write a function explicitly for 3-tuples. A general function to apply a 3-tuple of functions to a 3-tuple of values is
apply (f, g, h) (a, b, c) = (f a, g b, h c)
You have to explicitly write each function application because tuples don't have the recursive property of lists.
来源:https://stackoverflow.com/questions/26092198/haskell-apply-tuple-of-functions-to-tuple-of-values