How to Stump ChatGPT in 1 Easy Step (Hint: Ask a Windows Question)
While doing some research for Setup.hs, my new free course, I confronted a fact of Haskell development with Stack.
The commands for running individual test suites are cumbersome.
For example, if you have a parse-tests
suite in your Project.cabal
file, you can run it (without running other suites) like so:
$ stack build Project:test:parse-tests
The structure isn't hard once you're used to it, but remembering the exact names of your test suites isn't always easy on larger projects. This leads to the question:
How can I create aliases for 'stack build' commands?
On Unix-based systems, it's quite easy. Just slap something like this in your .bashrc
(or equivalent) and you're good to go:
alias ppt="stack build Project:test:parse-tests"
...
$ source ~/.bashrc
$ ppt
(Tests run)
Windows though is, as always, a special beast. And much as I generally prefer to use Windows Subsystem for Linux, I wanted to help any users who might be working with a pure Windows setup. This article will focus on:
How do I enable 'stack' aliases in Windows PowerShell?
Now, when I lay out the code I put in my PowerShell profile, it looks a little dense but fairly innocuous:
Function ProjectParseTest { Invoke-Expression "stack build Project:test:parse-tests" }
New-Alias -Name qpt -Value ProjectParseTest
But discovering the exact formula for getting all this to work was quite difficult. And as we'll see, in fact, even ChatGPT, the new kid on the block, struggles with this question. After a brief while struggling through Windows documentation, I turned to the chat bot. Let's review the first question:
ChatGPT Question 1
Me
How can I make command aliases in Windows 11 Powershell?
Chat GPT
You can create command aliases in Windows 11 PowerShell by using the
New-Alias
cmdlet. Here's an example that creates an alias ls for theGet-ChildItem
cmdlet:
New-Alias -Name ls -Value Get-ChildItem
This will create an alias named
ls
that can be used just like theGet-ChildItem
cmdlet. For example:
ls .
This will list the contents of the current directory, just as if you had typed
Get-ChildItem
..
To persist your alias across sessions, you need to add it to your PowerShell profile. To do that, first determine the path to your profile by running the following command:
$ $profile
If the profile does not exist yet, you can create it by running the following command:
New-Item -Type File -Path $profile -Force
Then, open the profile in your favorite text editor and add the New-Alias command. Save the file and restart your PowerShell session. Your alias will be available every time you start PowerShell.
Analysis
Now, everything Chat has told me is technically true. The command it gives successfully creates an alias. Notably though, if you want to try this yourself, you should use a different alias, as Powershell already includes the alias ls
in most recent Windows version (previously you would need to use the alias dir
to get that effect).
Additionally, I found that the PROFILE
variable was indeed set, but the file did not exist. In fact, the directory it was supposed to be in (Documents/WindowsPowerShell
) did not exist either! So you'll have to make that before creating the file. But placing an alias command in there will persist the alias across sessions.
However, notice that this doesn't quite answer our question, because the subject of the alias was an established Windows expression (Get-ChildItem
, also know as a cmdlet
), rather than a terminal command we would write.
Let's suppose we just want to alias sb=stack build
. It does not work to simply use a string for the command:
There are some clues to our eventual solution in the error message though. It tells us we need a cmdlet
, a function, a script file, or an operable program.
Now stack
by itself is an operable program. So we could actually do the following:
PS > New-Alias -Name st -Value "stack"
PS > st
(stack usage output)
But we want to provide arguments as part of the alias. So let's see if ChatGPT knows how. We'll see that its answers are not quite right.
ChatGPT Question 2
Me
How do I make the alias run a command, like "stack build"
Chat GPT
You can create an alias that runs a command by using the
Invoke-Expression
cmdlet to evaluate a string as a PowerShell expression. Here's an example that creates an aliassb
for thestack build
command:
New-Alias -Name sb -Value { Invoke-Expression "stack build" }
This will create an alias named
sb
that can be used to run thestack build
command. For example:
sb
This will run the
stack build
command, just as if you had typed it into the PowerShell prompt.
As with the previous example, you can add this alias to your PowerShell profile to persist it across sessions.
Me
I get an error "Cannot evaluate parameter 'Value' because its argument is specified as a script block and there is no input"
How do I specify input in this alias?
Chat GPT
To specify input in a script block alias, you can use the
Param
keyword to declare input parameters and then pass the input to the underlying command. Here's an example that creates an aliassb
for the stack build command, allowing you to specify the target to build as input:
New-Alias -Name sb -Value {
Param ($target)
Invoke-Expression "stack build $target"
}
This will create an alias named
sb
that can be used to run thestack build
command with a specified target. For example:
sb my-target
This will run the
stack build my-target
command, just as if you had typed it into the PowerShell prompt.
As with the previous examples, you can add this alias to your PowerShell profile to persist it across sessions.
Analysis
Both of the proposed approaches fail! I commented on the issue explicitly after the first response, and then got the same error running the second approach ("Cannot evaluate parameter 'Value' because its argument is specified as a script block..."). So I gave up on my interrogation and started searching for documentation again.
Solving the Problem
I don't remember exactly where I found the solution. I think it involved cobbling together points from multiple Stack Overflow posts. Windows documentation was not very helpful. Let's recall the error message from earlier:
The term 'stack build' is not recognized as the name of a cmdlet, function, script file, or operable program.
We can't make an official Windows PS cmdlet out of our program, nor can we make an operable program with the arguments we want. We could make a script file, but running scripts from PowerShell is surprisingly difficult (there are some extra steps with permissions). The answer is that we can make a function that our alias will refer to.
This function will, incidentally, use the Invoke-Expression
idea ChatGPT recommended as well, just not directly as the alias value!
The following code will go in our $PROFILE
. First, we make a function that invokes our expression. We can give this function an arbitrary name, but I used a capitalized name (ProjectParseTest
) to distinguish from any potential aliases.
Function ProjectParseTest { Invoke-Expression "stack build Project:test:parse-tests" }
Now we can use this function as the object of a New-Alias
call! So we use the command ChatGPT suggested, just substituting our function for the -Value
instead of providing a raw Invoke-Expression
command.
Function ProjectParseTest { Invoke-Expression "stack build Project:test:parse-tests" }
New-Alias -Name ppt -Value ProjectParseTest
This alias succeeds now, and by putting this in my PowerShell profile, I can persist the alias across sessions!
$ ppt
(Test runs)
Haskell on Windows
Now aliases are just one small piece of the Haskell puzzle. So if you're trying to get started with Haskell, but don't have a Mac, and aren't familiar with Linux, you might want to know:
How do I set up my Haskell toolchain on Windows?
My new free course Setup.hs goes over all the basics of setting up your Haskell toolchain, including how to get started with code hints in three of the most popular editors out there. Plus, every lecture includes a walkthrough video for Windows* so you can learn what kinds of odd quirks you might come across! You can read more about the course in this article.
Plus, if you subscribe to our monthly newsletter, you'll also get a 20% discount code for all our paid courses that is good until May 1! So don't miss out on your chance to learn about Haskell!
*Separate walkthrough videos for MacOS and Linux are also included.