Wishful thinking: a text editor that expands function applications into function definitions

So I was thinking about a "killer feature" for a text editor. Wouldn't it be neat if you could expand function calls into their definitions, in-place? For example, suppose we have "minus" defined like so, somewhere in another file:
minus (a, b, c) (x, y, z) = (a - x, b - y, c - z)
Later, we make use of the function in our current context:
let p1 = (1, 2, 3) p2 = (4, 5, 6) in p1 `minus` p2
By telling the editor to "expand" the minus, we get a temporary replacing of the above with:
(1 - 4, 2 - 5, 3 - 6)
Another example:
parse s = map readLine ls
And supposing that readLine is defined somewhere else, moving the cursor to readLine in the line above and "expanding" becomes:
parse s = map (\line -> words $ dropWhile (== ' ') line)
This is all pretty standard for the kinds of things we do in Haskell to work it out by hand, but is there any reason the parser couldn't do this? I think it would be even harder to do automatically in any other language. Maybe it's already been attempted or done? Curious, Duane Johnson

On Thu, 2009-04-02 at 18:01 -0600, Duane Johnson wrote:
So I was thinking about a "killer feature" for a text editor. Wouldn't it be neat if you could expand function calls into their definitions, in-place?
For example, suppose we have "minus" defined like so, somewhere in another file:
minus (a, b, c) (x, y, z) = (a - x, b - y, c - z)
Later, we make use of the function in our current context:
let p1 = (1, 2, 3) p2 = (4, 5, 6) in p1 `minus` p2
By telling the editor to "expand" the minus, we get a temporary replacing of the above with:
(1 - 4, 2 - 5, 3 - 6)
Another example:
parse s = map readLine ls
And supposing that readLine is defined somewhere else, moving the cursor to readLine in the line above and "expanding" becomes:
parse s = map (\line -> words $ dropWhile (== ' ') line)
This is all pretty standard for the kinds of things we do in Haskell to work it out by hand, but is there any reason the parser couldn't do this? I think it would be even harder to do automatically in any other language. Maybe it's already been attempted or done?
See HaRe http://www.cs.kent.ac.uk/projects/refactor-fp/hare.html

It seems like a neat feature, and it could just be my inexperience with
Haskell but it doesn't seem "killer". For example, why would you want to
expand readLine like that if you already have it defined? It seems to
defeat much of the benefit of functional languages in the first place, which
is that it's so easy to reuse code by composing functions into new
functions. I can see the case where you're passing all constants to a
function, because then supposedly inlining it might be more efficient, but I
would think the compiler would optimize most of the cases for you anyway.
One feature that I -do- think would be killer though, is the ability for the
editor to do a mouse-over tooltip of a) function definitions, and b)
arbitrary expressions. So like in your example above, hovering the mouse
over `minus` in the expression p1 `minus` p2 would pop up a two line tooltip
that looked like this
minus :: (Num a, Num b, Num c) => (a,b,c) -> (a,b,c) -> (a,b,c)
minus :: first -> second -> (a,b,c)
Something along those lines. It's nice to be able to see names of function
arguments without having to navigate away from the line you're editing.
This isn't the killer yet though since it's actually pretty standard for
most sufficiently advanced programming language IDEs. The killer is that
the mouse-over event would also look one line above the function definition
for a comment. It would then scan backward until it finds no more
comments. It would then display that text above the function definition.
It's great having a type signature, but comments would just be icing on the
cake.
For arbitrary expressions, suppose you had the following function:
replaceItem :: [a] -> (a -> Bool) -> a -> [a]
let replaceItem xs pred = (: filter (not.pred) xs)
You then highlight the text "filter (not.pred)" and hover over the
highlighted text. The mouse then pops up a tooltip that says "[a] -> [a]".
That would be killer IMO
On Thu, Apr 2, 2009 at 7:01 PM, Duane Johnson
So I was thinking about a "killer feature" for a text editor. Wouldn't it be neat if you could expand function calls into their definitions, in-place?
For example, suppose we have "minus" defined like so, somewhere in another file:
minus (a, b, c) (x, y, z) = (a - x, b - y, c - z)
Later, we make use of the function in our current context:
let p1 = (1, 2, 3)
p2 = (4, 5, 6) in p1 `minus` p2
By telling the editor to "expand" the minus, we get a temporary replacing of the above with:
(1 - 4, 2 - 5, 3 - 6)
Another example:
parse s = map readLine ls
And supposing that readLine is defined somewhere else, moving the cursor to readLine in the line above and "expanding" becomes:
parse s = map (\line -> words $ dropWhile (== ' ') line)
This is all pretty standard for the kinds of things we do in Haskell to work it out by hand, but is there any reason the parser couldn't do this? I think it would be even harder to do automatically in any other language. Maybe it's already been attempted or done?
Curious,
Duane Johnson
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Perhaps it wouldn't be as all-wonderful as I think, but as a "new" Haskell user, I am constantly switching back and forth between various definitions of things trying to compare documentation and files... The purpose of "expansion" as I was explaining it is not to *permanently replace* what is in the text, but rather to *temporarily replace* it. I imagine it kind of like a "zoom in" for code. You could "zoom in" on one function, and seeing a new function that you don't recognize, "zoom in" again, and so on. Once done, you would hit "ESC" to make it all return as it was. BTW, I do like your suggestion of tooltip types. That would be very handy! Duane Johnson On Apr 2, 2009, at 6:24 PM, Zachary Turner wrote:
It seems like a neat feature, and it could just be my inexperience with Haskell but it doesn't seem "killer". For example, why would you want to expand readLine like that if you already have it defined? It seems to defeat much of the benefit of functional languages in the first place, which is that it's so easy to reuse code by composing functions into new functions. I can see the case where you're passing all constants to a function, because then supposedly inlining it might be more efficient, but I would think the compiler would optimize most of the cases for you anyway.
One feature that I -do- think would be killer though, is the ability for the editor to do a mouse-over tooltip of a) function definitions, and b) arbitrary expressions. So like in your example above, hovering the mouse over `minus` in the expression p1 `minus` p2 would pop up a two line tooltip that looked like this
minus :: (Num a, Num b, Num c) => (a,b,c) -> (a,b,c) -> (a,b,c) minus :: first -> second -> (a,b,c)
Something along those lines. It's nice to be able to see names of function arguments without having to navigate away from the line you're editing. This isn't the killer yet though since it's actually pretty standard for most sufficiently advanced programming language IDEs. The killer is that the mouse-over event would also look one line above the function definition for a comment. It would then scan backward until it finds no more comments. It would then display that text above the function definition. It's great having a type signature, but comments would just be icing on the cake.
For arbitrary expressions, suppose you had the following function:
replaceItem :: [a] -> (a -> Bool) -> a -> [a] let replaceItem xs pred = (: filter (not.pred) xs)
You then highlight the text "filter (not.pred)" and hover over the highlighted text. The mouse then pops up a tooltip that says "[a] -
[a]". That would be killer IMO
On Thu, Apr 2, 2009 at 7:01 PM, Duane Johnson
wrote: So I was thinking about a "killer feature" for a text editor. Wouldn't it be neat if you could expand function calls into their definitions, in-place? For example, suppose we have "minus" defined like so, somewhere in another file:
minus (a, b, c) (x, y, z) = (a - x, b - y, c - z)
Later, we make use of the function in our current context:
let p1 = (1, 2, 3) p2 = (4, 5, 6) in p1 `minus` p2
By telling the editor to "expand" the minus, we get a temporary replacing of the above with:
(1 - 4, 2 - 5, 3 - 6)
Another example:
parse s = map readLine ls
And supposing that readLine is defined somewhere else, moving the cursor to readLine in the line above and "expanding" becomes:
parse s = map (\line -> words $ dropWhile (== ' ') line)
This is all pretty standard for the kinds of things we do in Haskell to work it out by hand, but is there any reason the parser couldn't do this? I think it would be even harder to do automatically in any other language. Maybe it's already been attempted or done?
Curious,
Duane Johnson
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

2009/4/3 Duane Johnson
Perhaps it wouldn't be as all-wonderful as I think, but as a "new" Haskell user, I am constantly switching back and forth between various definitions of things trying to compare documentation and files... The purpose of "expansion" as I was explaining it is not to *permanently replace* what is in the text, but rather to *temporarily replace* it. I imagine it kind of like a "zoom in" for code. You could "zoom in" on one function, and seeing a new function that you don't recognize, "zoom in" again, and so on. Once done, you would hit "ESC" to make it all return as it was.
Sounds exactly like the F9 feature in Excel (that's where you got the idea, right?). I can personally attest that it can be an incredibly useful feature. Michael

On Thu, Apr 2, 2009 at 9:33 PM, Michael Snoyman
2009/4/3 Duane Johnson
Perhaps it wouldn't be as all-wonderful as I think, but as a "new" Haskell user, I am constantly switching back and forth between various definitions of things trying to compare documentation and files... The purpose of "expansion" as I was explaining it is not to *permanently replace* what is in the text, but rather to *temporarily replace* it. I imagine it kind of like a "zoom in" for code. You could "zoom in" on one function, and seeing a new function that you don't recognize, "zoom in" again, and so on. Once done, you would hit "ESC" to make it all return as it was.
Sounds exactly like the F9 feature in Excel (that's where you got the idea, right?). I can personally attest that it can be an incredibly useful feature.
Michael
I actually wasn't thinking about temporarily replacing it. That sounds cooler than how I originally interpreted it :)

I hadn't seen that feature in Excel before. When I press F9 it seems to evaluate the expression, which isn't quite what I had in mind (Mac OS). Is that the same as what you get? Duane On Apr 2, 2009, at 8:33 PM, Michael Snoyman wrote:
2009/4/3 Duane Johnson
Perhaps it wouldn't be as all-wonderful as I think, but as a "new" Haskell user, I am constantly switching back and forth between various definitions of things trying to compare documentation and files... The purpose of "expansion" as I was explaining it is not to *permanently replace* what is in the text, but rather to *temporarily replace* it. I imagine it kind of like a "zoom in" for code. You could "zoom in" on one function, and seeing a new function that you don't recognize, "zoom in" again, and so on. Once done, you would hit "ESC" to make it all return as it was.
Sounds exactly like the F9 feature in Excel (that's where you got the idea, right?). I can personally attest that it can be an incredibly useful feature.
Michael

On Fri, Apr 3, 2009 at 7:07 AM, Duane Johnson
I hadn't seen that feature in Excel before. When I press F9 it seems to evaluate the expression, which isn't quite what I had in mind (Mac OS). Is that the same as what you get? Duane
Yeah, it's the same feature. It's just that in Excel, the functions always return a value, not an expression. For example, a VLOOKUP doesn't call other Excel functions to return the result, it simply calculates what you're looking for. Hope that made sense. Michael

One word says more than a thousand pictures: Vim http://www.vim.org/. (well, okay, I'm sure Emacs will do just as well, and some of the more recent IDEs seem to be catching up;-) plus plugins, of course!-) - unfolding definitions: if you really want that, it is in the domain of program transformation systems and refactorers (HaRe, the Haskell refactorer, has been mentioned - it worked on Haskell'98 sources, plugging into Vim or Emacs; it would really be great to have funding for porting that to a modern GHC/Cabal-based environment, but if you're happy with Haskell'98, and have all the sources, the old HaRe should still do the job once you get it to build with recent GHCs/libraries) - looking up definitions: that is supported in various ways in Vim/Emacs and the like - I'll talk about some Vim examples, as that is what I use. - tag files (generated by running tools like 'ghc -e :ctags', hasktags,.. over the sources) are a simple database linking identifiers to definition sites. Based on these, one can jump from identifiers to definitions (keeping a stack of locations, so one can go back easily), or open split windows on the definition sites. See the "Moving through programs" section in Vim's help, also online at: http://vimdoc.sourceforge.net/htmldoc/usr_29.html . - the haskellmode plugins for Vim support documentation lookup (opening the haddocs for the identifier under cursor in a browser), and the documentation provides source links, if the docs themselves aren't sufficient. Useful for all those sourceless package installations. - the haskellmode plugins also support type tooltips (or, if you don't like tooltips, or are working in a terminal without gui, type signatures can be displayed in the status line, or added to the source code). This is currently based on GHCi's :browse!, though, so you can only get the types of toplevel definitions that way. One of the insertmode completions also displays types. - if you explain Haskell's import syntax to Vim, you can also search in (local) imported files, using Vim's standard keyword search, for instance ([I). The haskellmode plugins for Vim are currently in the process of moving to http://projects.haskell.org/haskellmode-vim/ . Which made me notice that I hadn't updated the publicly available version in quite some time (announcement to follow when that process has settled down somewhat). Claus
participants (5)
-
Claus Reinke
-
Derek Elkins
-
Duane Johnson
-
Michael Snoyman
-
Zachary Turner