quickcheck icon indicating copy to clipboard operation
quickcheck copied to clipboard

‘apply’ and ‘Fn’ for different arities

Open Icelandjack opened this issue 8 years ago • 3 comments

The following are used in containers

apply2 :: Fun (a, b) c -> a -> b -> c
apply2 f a b = apply f (a, b)

apply3 :: Fun (a, b, c) d -> a -> b -> c -> d
apply3 f a b c = apply f (a, b, c)

I see two directions we can go. We can supply those functions, along with:

pattern Fn :: (a -> b) -> Fun a b
pattern Fn f <- Fun _ f

pattern Fn2 :: (a -> b -> c) -> Fun (a, b) c
pattern Fn2 f <- Fun _ (curry -> f)

pattern Fn3 :: (a -> b -> c -> d) -> Fun (a, b, c) d
pattern Fn3 f <- Fun _ (curry3 -> f)

curry3 f a b c = f (a, b, c)

now it can be written

pInsertWithKeyStrict :: Fun (Int, Int) Int -> Int -> IntMap Int -> Bool
pInsertWithKeyStrict (Fn2 f) v m = isBottom $ M.insertWith f bottom v m

pInsertLookupWithKeyKeyStrict :: Fun (Int, Int, Int) Int -> Int -> IntMap Int -> Bool
pInsertLookupWithKeyKeyStrict (Fn3 f) v m = isBottom $ M.insertLookupWithKey f bottom v m

Alternatively we could use some type class trickery to provide a single function and pattern that supersede apply{,2,3} and Fn{,2,3}. So that the user never has to think about how many arguments their function has.

I have some doubts about the effects that will have on inference.


One last solution: somehow define an Arbitrary (Fun a (b -> c)) instance. I have not thought this through but if this makes sense it might be the most elegant solution.

Icelandjack avatar Sep 01 '16 13:09 Icelandjack

Silly me, we actually do have an instance for functions

Sub Dict :: (Function a, CoArbitrary a, CoArbitrary b, Arbitrary c) :- Arbitrary (Fun a (b -> c))

so we can generate them just fine (arbitrary @(Fun Int (Bool -> Int))), the problem is showing them!

I am not familiar with the internals of the library, this is my attempt at a Show instance that curries (it indicates that we would actually need Show (Fun a (b :-> c)))

-- Doesn't work as intended
instance {-# OVERLAPPING #-} (Show a, Show b, Show c, Function b) => Show (Fun a (b -> c)) where
 show = \case
  Fun (_, _, False) _ -> "<fun>"
  -- ↓ incorrect
  Fun (f, _, True) _ -> showFunction (Pair (fmap function f)) Nothing

Any thoughts?

Icelandjack avatar Sep 01 '16 14:09 Icelandjack

@Icelandjack we can generate and show Fun a (Fun b c) but that's about the same as Fun (a, b) c.

I'd like apply2 and apply3, and the patterns.

Doing trickery is :-1: Maybe it will work with e.g. http://hackage.haskell.org/package/HList-0.4.1.0/docs/Data-HList-HCurry.html#v:hCurry but that functionality could be in a separate package, or at least tried somewhere to prove being useful and unproblematic.

phadej avatar Sep 01 '16 15:09 phadej

Agreed, I'll make a PR with apply*, Fn* but I'd like to leave this open for further discussions

Icelandjack avatar Sep 01 '16 15:09 Icelandjack