Tab and Shift-Tab smart indent on selected text - haskell

It's standard in most modern editors that you can highlight a piece of code and indent or unindent a tab or however many spaces you're using; how do you do this in emacs?
So, for example I just opened sublime text, highlighted the following piece of code:
variation1 person phoneMap carrierMap addressMap =
case M.lookup person phoneMap of
Nothing -> Nothing
Just number ->
case M.lookup number carrierMap of
Nothing -> Nothing
Just carrier -> M.lookup carrier addressMap
then pressed tab and got
variation1 person phoneMap carrierMap addressMap =
case M.lookup person phoneMap of
Nothing -> Nothing
Just number ->
case M.lookup number carrierMap of
Nothing -> Nothing
Just carrier -> M.lookup carrier addressMap
one shift-tab on that code returns it back to where it was, and if I continuing pressing shift-tab I eventually get the following:
variation1 person phoneMap carrierMap addressMap =
case M.lookup person phoneMap of
Nothing -> Nothing
Just number ->
case M.lookup number carrierMap of
Nothing -> Nothing
Just carrier -> M.lookup carrier addressMap
Quote from another response:
emacs language modes don't really have a notion of 'indent this block
1 tab further'. Instead they're very opinionated and have a notion of
'this is the correct indentation' and that's what you get when you hit
tab in a language mode.
Except when I do that with the following code (haskell mode and ghc mod enabled):
import Monad
import System
import IO
import Random
import Control.Monad.State
type RandomState a = State StdGen a
data CountedRandom = CountedRandom {
crGen :: StdGen
, crCount :: Int
}
type CRState = State CountedRandom
getRandom :: Random a => RandomState a
getRandom =
get >>= \gen ->
let (val, gen') = random gen in
put gen' >>
return val
I get the following:
import Monad
import System
import IO
import Random
import Control.Monad.State
type RandomState a = State StdGen a
data CountedRandom = CountedRandom {
crGen :: StdGen
, crCount :: Int
}
type CRState = State CountedRandom
getRandom :: Random a => RandomState a
getRandom =
get >>= \gen ->
let (val, gen') = random gen in
put gen' >>
return val
when I wanted
import Monad
import System
import IO
import Random
import Control.Monad.State
type RandomState a = State StdGen a
data CountedRandom = CountedRandom {
crGen :: StdGen
, crCount :: Int
}
type CRState = State CountedRandom
getRandom :: Random a => RandomState a
getRandom =
get >>= \gen ->
let (val, gen') = random gen in
put gen' >>
return val
Near enough to a solution from ataylor:
(defcustom tab-shift-width 4
"Sets selected text shift width on tab"
:type 'integer)
(make-variable-buffer-local 'tab-shift-width)
(global-set-key
(kbd "<tab>")
(lambda (start end)
(interactive "r")
(if (use-region-p)
(save-excursion
(let ((deactivate-mark nil))
(indent-rigidly start end tab-shift-width)))
(indent-for-tab-command))))
(global-set-key
(kbd "S-<tab>")
(lambda (start end)
(interactive "r")
(if (use-region-p)
(save-excursion
(let ((deactivate-mark nil))
(indent-rigidly start end (- tab-shift-width))))
(indent-for-tab-command))))
It'd be nice if emacs had support for indent detection (i.e., just grab the value of some variable); the closest thing I found to this was a plugin called dtrt indent but it doesn't work for Haskell.

indent-region will reindent a block of text according to the current mode.
To force an indentation level to be added, you can use string-rectangle, which will prompt you for a string. Here you can provide the string for an indentation level (e.g. a tab, 4 spaces, etc.). The string will be inserted on each line of the currently selected region, in the current column, effectively indenting it. Alternatively, you can get a similar effect from open-rectangle, which will insert whitespace into the rectangle with corners defined by the point and the mark.
Another way to force indentation is to call indent-rigidly (C-x TAB). This overrides the mode specific indentation rules and indents a fixed amount. The numeric argument specifies how much to indent, and a negative argument will unindent. If you want this to be the default behavior when a region is selected, you could do something like this:
(global-set-key
(kbd "<tab>")
(lambda (start end)
(interactive "r")
(if (use-region-p)
(save-excursion
(let ((deactivate-mark nil))
(indent-rigidly start end 4)))
(indent-for-tab-command))))

Haskell code is incredibly difficult to indent correctly, because there are multiple "correct" indentations for a piece of code.
haskell-mode has a very specific line format that it expects you to follow (As in, you have to make line breaks in the right places) and it has a few indentation rules for formatting code that matches that line format. These rules exist to make the automatic indentation results more consistent. The rules are roughly this:
After every keyword that introduces a block, you should make a line break or make sure that the entire block fits into the layout. Otherwise, you get a lot of hanging blocks like in your getRandom example
All blocks are indented exactly two spaces. This includes module blocks; if you do module Bla where, the whole part after that line will be indented. This means that you should keep the default Haskell module file format for the indentation order to work out.
The indentation of a line needs to be as unambiguous as possible; if a line could mean different things depending on its indentation, it will lead to it being indented to the position that haskell-mode thinks makes sense in the context. Fixing this can be impossible in some cases.
Because it is impossible to structure Haskell code so that it meets the requirements of haskell-mode, you cannot indent a while Haskell code file like this. You need to only use automatic indentation locally. This can be done in a number of ways:
When you are on a line, you can indent the current line to the most likely "correct" position with regards to the previous line by pressing TAB. By pressing TAB again, you will bring the line to the "next" indentation level, and continuously cycle through all possible logical indentation steps.
If you select a series of blocks that are found locally (The body of a function etc.) and use M-x indent-region, the result will most likely be correct.
What I usually do in a situation like this is to start on the line that has the "wrong" indentation, press TAB once, and go down line-by-line, pressing TAB one or multiple times on each line until the indentation of that line is correct. The current "logical indentation positions" for the current line are calculated from the preceding code context, so correcting the indentation from the top almost always yields the correct result.

I highlight the area and hit C-M-\. It is indent-region and more fun can be found at the multi-line indent page.

emacs language modes don't really have a notion of 'indent this block 1 tab further'. Instead they're very opinionated and have a notion of 'this is the correct indentation' and that's what you get when you hit tab in a language mode.
Once you get used to it anything else seems weird. In your Haskell code those case statements only really have one indentation that's valid, anything else is a syntax error unless you add braces and semicolons. If you really want to customize what emacs considers the 'right' indentation look at how to customize your mode. A lot of language modes reuse the c-mode variables so here is probably a good place to start (though I'm not sure what Haskell mode does, I've never found a need to customize it).
edit:
I see in your comment that your troubles are from not having Haskell mode installed, got to the github page to get it.

Related

set variable to the same variable modified?

I have a program I'm trying to create of a one line text editor
I've come to a bit of a wall at this point.
I have a list of letters called left and one called right
perhaps in a function or a do list how can I set left to left ++ char where char is a user inputted char. I understand it's not possible to modify lists but can I redefine them?
If this pseudo code helps
left = "hello"
in = get user input
left = left ++ in
Thanks in advance
This is what the State Monad is for. The link should help (it points to a tutorial). Your example would then become:
type Line = State String ()
addInput :: String -> Line
addInput inp = do
left <- get
put $ left ++ inp
runState (addInput <user input>) "hello"
This does, however, require getting to know monads a bit. Follow the examples in the link.

Haskell parse error on input '=' for quadratic formula [duplicate]

I often read that I shouldn't mix tabs and spaces in Haskell, or that I shouldn't use tabs at all. Why?
The problem is twofold. First of all, Haskell is indentation sensitive, e.g. the following code isn't valid:
example = (a, b)
where
a = "Hello"
b = "World"
Both bindings need to be indented with the same number of spaces/tabs (see off-side rule). While it's obvious in this case, it's rather hidden in the following one, where I denote a space by · and a tab by »:
example = (a, b)
··where
····a = "Hello"
» b = "World"
This will look like valid Haskell code if the editor will show tabs aligned to multiples by four. But it isn't. Haskell tabs are aligned by multiples of eight, so the code will be interpreted like this:
example = (a, b)
··where
····a = "Hello"
» b = "World"
Second, if you use only tabs, you can end up with a layout that doesn't look right. For example, the following code looks correct if a tab gets displayed with six or more spaces (eight in this case):
example = (a, b)
» where» a = "Hello"
» » b = "World"
But in another editor that uses 4 spaces it won't look right anymore:
example = (a, b)
» where» a = "Hello"
» » b = "World"
It's still correct, though. However, someone who's used to spaces might reindent b' binding with spaces and end up with a parser error.
If you enforce a code convention throughout your code that makes sure that you only use tabs at the beginning of a line and use a newline after where, let or do you can avoid some of the problems (see 11). However, current releases of GHC warn about tabs by default, because they have been a source of many parser errors in the past, so you probably want to get rid of them too.
See also
A reddit thread on the topic (majority pro spaces, but some pro tabs)
Good Haskell Style (pro spaces)
Yet Another Tabs v Space debate (pro mixing)

Order of execution within monads

I was learning how to use the State monad and I noticed some odd behavior in terms of the order of execution. Removing the distracting bits that involve using the actual state, say I have the following code:
import Control.Monad
import Control.Monad.State
import Debug.Trace
mainAction :: State Int ()
mainAction = do
traceM "Starting the main action"
forM [0..2] (\i -> do
traceM $ "i is " ++ show i
forM [0..2] (\j -> do
traceM $ "j is " ++ show j
someSubaction i j
)
)
Running runState mainAction 1 in ghci produces the following output:
j is 2
j is 1
j is 0
i is 2
j is 2
j is 1
j is 0
i is 1
j is 2
j is 1
j is 0
i is 0
Outside for loop
which seems like the reverse order of execution of what might be expected. I thought that maybe this is a quirk of forM and tried it with sequence which specifically states that it runs its computation sequentially from left to right like so:
mainAction :: State Int ()
mainAction = do
traceM "Outside for loop"
sequence $ map handleI [0..2]
return ()
where
handleI i = do
traceM $ "i is " ++ show i
sequence $ map (handleJ i) [0..2]
handleJ i j = do
traceM $ "j is " ++ show j
someSubaction i j
However, the sequence version produces the same output. What is the actual logic in terms of the order of execution that is happening here?
Haskell is lazy, which means things are not executed immediately. Things are executed whenever their result is needed – but no sooner. Sometimes code isn't executed at all if its result isn't needed.
If you stick a bunch of trace calls in a pure function, you will see this laziness happening. The first thing that is needed will be executed first, so that's the trace call you see first.
When something says "the computation is run from left to right" what it means is that the result will be the same as if the computation was run from left to right. What actually happens under the hood might be very different.
This is in fact why it's a bad idea to do I/O inside pure functions. As you have discovered, you get "weird" results because the execution order can be pretty much anything that produces the correct result.
Why is this a good idea? When the language doesn't enforce a specific execution order (such as the traditional "top to bottom" order seen in imperative languages) the compiler is free to do a tonne of optimisations, such as for example not executing some code at all because its result isn't needed.
I would recommend you to not think too much about execution order in Haskell. There should be no reason to. Leave that up to the compiler. Think instead about which values you want. Does the function give the correct value? Then it works, regardless of which order it executes things in.
I thought that maybe this is a quirk of forM and tried it with sequence which specifically states that it runs its computation sequentially from left to right like so: [...]
You need to learn to make the following, tricky distinction:
The order of evaluation
The order of effects (a.k.a. "actions")
What forM, sequence and similar functions promise is that the effects will be ordered from left to right. So for example, the following is guaranteed to print characters in the same order that they occur in the string:
putStrLn :: String -> IO ()
putStrLn str = forM_ str putChar >> putChar '\n'
But that doesn't mean that expressions are evaluated in this left-to-right order. The program has to evaluate enough of the expressions to figure out what the next action is, but that often does not require evaluating everything in every expression involved in earlier actions.
Your example uses the State monad, which bottoms out to pure code, so that accentuates the order issues. The only thing that a traversal functions such as forM promises in this case is that gets inside the actions mapped to the list elements will see the effect of puts for elements to their left in the list.

Ungroupable line break using wl-pprint

I'm writing a pretty-printer for a simple white-space sensitive language.
I like the Leijen pretty-printer library more than I like the Wadler library, but the Leijen library has one problem in my domain: any line break I insert may be overridden by the group construct, which may compress any line, which might change the semantics of the output.
I don't think I can implement an ungroupable line in the wl-pprint (although I'd love to be wrong).
Looking a bit at the wl-pprint-extras package, I don't think that even the exposed internal interface allows me to create a line which will not be squashed by group.
Do I just have to rely on the fact that I never use group, or do I have some better option?
Given that you want to be able to group and you also need to be able to ensure some lines aren't uninserted,
why don't we use the fact that the library designers encoded the semantics in the data type,
instead of in code. This fabulous decision makes it eminently re-engineerable.
The Doc data type encodes a line break using the constructor Line :: Bool -> Doc.
The Bool represents whether to omit a space when removing a line. (Lines indent when they're there.)
Let's replace the Bool:
data LineBehaviour = OmitSpace | AddSpace | Keep
data Doc = ...
...
Line !LineBehaviour -- not Bool any more
The beautiful thing about the semantics-as-data design is that if we replace
this Bool data with LineBehaviour data, functions that didn't use it but
passed it on unchanged don't need editing. Functions that look inside at what
the Bool is break with the change - we'll rewrite exactly the parts of the code
that need changing to support the new semantics by changing the data type where
the old semantics resided. The program won't compile until we've made all the
changes we should, while we won't need to touch a line of code that doesn't
depend on line break semantics. Hooray!
For example, renderPretty uses the Line constructor, but in the pattern Line _,
so we can leave that alone.
First, we need to replace Line True with Line OmitSpace, and Line False with Line AddSpace,
line = Line AddSpace
linebreak = Line OmitSpace
but perhaps we should add our own
hardline :: Doc
hardline = Line Keep
and we could perhaps do with a binary operator that uses it
infixr 5 <->
(<->) :: Doc -> Doc -> Doc
x <-> y = x <> hardline <> y
and the equvalent of the vertical seperator, which I can't think of a better name than very vertical separator:
vvsep,vvcat :: [Doc] -> Doc
vvsep = fold (<->)
vvcat = fold (<->)
The actual removing of lines happens in the group function. Everything can stay the same except:
flatten (Line break) = if break then Empty else Text 1 " "
should be changed to
flatten (Line OmitSpace) = Empty
flatten (Line AddSpace) = Text 1 " "
flatten (Line Keep) = Line Keep
That's it: I can't find anything else to change!
You do need to avoid group, yes. The library's designed to facilitate wrapping or not wrapping based on the width of the output that you specify.
Dependent on the syntax of language you're implementing, you should also be cautious about softline and softbreak and the </> and <//> operators that use them. There's no reason I can see that you can't use <$> and <$$> instead.
sep, fillSep, cat and fillCat all use group directly or indirectly (and have the indeterminate semantics/width-dependent line breaks you want to avoid). However, given the your purpose, I don't think you need them:
Use vsep or hsep instead of sep or fillSep.
Use hcat or vcat instead of cat or fillCat.
You could use a line like
import Text.PrettyPrint.Leijen hiding (group,softline,softbreak,
(</>),(<//>),
sep,fillSep,cat,fillCat)
to make sure you don't call these functions.
I can't think of a way to ensure that functions you do use don't call group somewhere along the line, but I think those are the ones to avoid.

Simple Haskell program causes 'Illegal signature in pattern' error

I've decided to teach myself Haskell and I have never been so frustrated in all my life. I am going through the tutorial at http://lisperati.com/haskell/ which is the easiest one I could find. All that I am trying to do is read a text file called people.txt which contains a list of numbers and print the length of the list. This code is straight from the tutorial.
import Data.List
type Person = [Int]
main = do
people_text <- readFile "people.txt"
let people :: [Person]
people = read people_text
putStr "Number of people "
putStr (length people_text)
When I try to run the file with runHaskell tutorial03.hs I get this error message
tutorial03.hs:9:13:
Illegal signature in pattern: [Person] people
Use -XScopedTypeVariables to permit it
Using the XScopedTypeVariables flag I get
tutorial03.hs:10:17: Not in scope: type variable `people'
Could someone please explain what I am doing wrong.
Luqui's right that indentation is the issue. The compiler is treating your definition as if it were
let people :: [Person] people = read people_text
which does indeed look like you're writing a type signature in a pattern (and using people both as the function name and a pattern variable, to boot -- peculiar but permitted!).
Crucially, let is a layout keyword, introducing a block of lines which should all be indented to the same horizontal position. By following the signature with a more-indented line, you indicate that you're contuing the line with the signature, rather than starting a new line for the actual definition. If you don't like this fussy layout convention, you can use noisy semicolons.
If you want your definition to be treated as two lines, you either need to be careful to line up the peoples vertically...
let people :: [Person]
people = read people_text
or to signal the line ending explicitly with a semicolon.
let people :: [Person] ;
people = read people_text
The former would be preferable, although I expect most Haskellers would just supply a type annotation for read people_text rather than a signature for the definition, like this:
let people = read people_text :: [Person]
Once you've fixed that, you'll need to contend with the fact that the length of the list is a number, but putStr outputs strings. The print command may be more useful for this purpose.
change it to this, works for me:
...
let people :: [Person]
people = read people_text
...
print (length people_text)

Resources