
I don't know if it's the sheer number of updates to this ticket, but
#12363: Type application for infix -------------------------------------+------------------------------------- Reporter: Iceland_jack | Owner: Type: feature request | Status: new Priority: lowest | Milestone: Component: Compiler | Version: 8.0.1 (Parser) | Keywords: Resolution: | TypeApplications Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by Iceland_jack): Replying to [comment:15 rwbarton]: this syntax is starting to look fairly natural to me. Just According to Keikaku.⁽¹⁾ ⁽¹⁾ [https://www.reddit.com/r/OutOfTheLoop/comments/467byi/what_the_hell_is_keika... (Translator's note: keikaku means plan)]
Most of these examples don't look like code I would ever write, but the {{{`catch` @IOException}}} example is pretty sweet.
It works especially well with operators where the specified type does not appear in the return type: having to privilege one side over the other feels asymmetric, the [https://hackage.haskell.org/package/intervals intervals] package documentation gives a lot of good examples where this is useful: {{{#!hs -- >>> (5 ... 10 :: Interval Double)
(5 ... 0)
-- >>> (20 ... 40 :: Interval Double) `contains` (15 ... 35 :: Interval Double) -- False
(20 ... 40) `contains` @Double (15 ... 35) False }}}
but also simpler examples, I will avoid writing an explicit annotation if I can {{{#!hs -- >>> (0.1 :: Float) + 0.2 == 0.3 -- True
0.1 + 0.2 == @Float 0.3 True
-- >>> 0.1 + 0.2 == (0.3 :: Double) -- False
0.1 + 0.2 == @Double 0.3 False
-- >>> 0 `elem` [1,2::Int,3] -- False
0 `elem` @[] @Int [1,2,3] False }}}
For most examples you can easily annotate some other part of the expression to get the same effect. My experience is that infix type application leads to less thinking, more consistency (in where the type goes) and more resistance to change: I prefer the uncommented versions {{{#!hs -- n `hashWithSalt` (fromIntegral (ptrToIntPtr s) :: Int) -- n `hashWithSalt` fromIntegral @_ @Int (ptrToIntPtr s) n `hashWithSalt` @Int fromIntegral (ptrToIntPtr s) }}} {{{#!hs -- Var a -> digest c (1 :: Word8) `digest` a -- App f x -> digest c (2 :: Word8) `digest` f `digest` x -- HardType h -> digest c (3 :: Word8) `digest` h -- Forall k tvs cs b -> digest c (4 :: Word8) `digest` k `digest` tvs `digest` cs `digest` b -- Loc _ ty -> digest c ty -- Exists k tvs cs -> digest c (5 :: Word8) `digest` k `digest` tvs `digest` cs -- And xs -> digest c (6 :: Word8) `digest` xs Var a -> c `digest` @Word8 1 `digest` a App f x -> c `digest` @Word8 2 `digest` f `digest` x HardType h -> c `digest` @Word8 3 `digest` h Forall k tvs cs b -> c `digest` @Word8 4 `digest` k `digest` tvs `digest` cs `digest` b Loc _ ty -> c `digest` ty Exists k tvs cs -> c `digest` @Word8 5 `digest` k `digest` tvs `digest` cs And xs -> c `digest` @Word8 6 `digest` xs }}} and {{{#!hs -- tAG_BITS_MAX = (1 `shiftL` tAG_BITS) :: Int tAG_BITS_MAX = 1 `shiftL` @Int tAG_BITS }}} ---- I would still say the main usefulness is pedagogy: I will not introduce invalid syntax when explaining things to newcomers, but for questions like [https://www.reddit.com/r/haskellquestions/comments/5mtk8v/instance_eq_questi... this] {{{#!hs Nodo x ys zs == Nodo x' ys' zs' = x == x' && ys == ys' && zs == zs' }}} maybe it would help to write it like this, to show the different instantiations of `==` {{{#!hs Nodo x ys zs == Nodo x' ys' zs' = x == @a x' && ys == @(Heap a) ys' && zs == @(Heap a) zs' }}} In the end it's up to what the community thinks -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12363#comment:16 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler