Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

‘apply’ and ‘Fn’ for different arities #110

Open
Icelandjack opened this issue Sep 1, 2016 · 3 comments
Open

‘apply’ and ‘Fn’ for different arities #110

Icelandjack opened this issue Sep 1, 2016 · 3 comments

Comments

@Icelandjack
Copy link
Contributor

Icelandjack commented Sep 1, 2016

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
Copy link
Contributor Author

Icelandjack commented Sep 1, 2016

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?

@phadej
Copy link
Contributor

phadej commented Sep 1, 2016

@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 👎 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.

@Icelandjack
Copy link
Contributor Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants