Posts tagged programming language


Tutorial: PowerShell Modules in FSharp

:: dotnet, fsharp, powershell, programming language, tutorial

By: Maciej Barć

F# is a amazing functional language bridging C#/.NET ecosystem with OCaml and interactive programming. It has recently became by favorite language to create personal projects in. It both has additional security of strong typing, unlike Python or Ruby while keeping the functional and interactive properties of weak-typed languages. F# is truly a engineering marvel.

PowerShell 7 is the Open-Source implementation of the old Windows PowerShell that is also cross-platform and can be used for scripting and automation. It’s Object-orientation makes an amazing extension capability compared to Bash.

You can use the F# language to create PowerShell modules. Normally PS Modules are written in C# but since the interop between .NET languages is insanely fluent one can just swap C# for F#.

Creating new project

mkdir -p ~/source/temporary/powershell-modules/fs-example
cd ~/source/temporary/powershell-modules/fs-example

Dotnet ClassLib

Init new F# Class project:

dotnet new classlib --language "F#"

Dependencies

Add dependency on Powershell interaction library:

dotnet add package PowerShellStandard.Library --version 5.1.1

F# interaction with PowerShell

Let’s rewrite Library.fs to contain:

namespace FsExample.PowerShell

open System.Management.Automation

[<Cmdlet(VerbsCommon.Format, "FsExample")>]
type FsExample() =
    inherit PSCmdlet()

    [<Parameter>]
    [<ValidateNotNullOrEmpty>]
    member val Name: string = "Me" with get, set

    override this.BeginProcessing() =
        printfn "Hello %s" this.Name

Then, change RootNamespace to the main module name, that is FsExample.PowerShell.

We need to copy all assemblies to output. Add <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net9.0</TargetFramework>
    <RootNamespace>FsExample.PowerShell</RootNamespace>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>

    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
  </PropertyGroup>

  <!-- Snip ... -->

</Project>

PowerShell library

Create PSModuleAssets directory:

mkdir -p PSModuleAssets
cd PSModuleAssets

The main module file will in turn load the DLL compiled form above F# code.

Create main module file - fs-example.psm1:

#!/usr/bin/env -S pwsh -NoLogo -NoProfile -NonInteractive

Import-Module "$PSScriptRoot/fs-example.dll"

We then need to create the main manifest file fs-example.psd1.

  • Path - relative path to output the manifest,
  • RootModule - relative module path to load on module import,
  • ModuleVersion, Description, Author and Copyright are some of standard metadata fields,
  • AliasesToExport, CmdletsToExport, DscResourcesToExport, FunctionsToExport and VariablesToExport are either globs or lists that tell what functions will be available on module load, for simplicity we will just specify a glob expression '*'.
New-ModuleManifest -Path ./fs-example.psd1 -RootModule ./fs-example.psm1 `
    -ModuleVersion "1.0.0" `
    -Description "FSharp example module" `
    -Author "Me" -Copyright "Copyright (c) 2025, Me" `
    -AliasesToExport '*' -CmdletsToExport '*' `
    -DscResourcesToExport '*' -FunctionsToExport '*' -VariablesToExport '*'

Copying PowerShell assets

Following ItemGroup will copy all files from PSModuleAssets to the output directory:

<Project Sdk="Microsoft.NET.Sdk">

  <!-- Snip ... -->

  <ItemGroup>
    <None Include="PSModuleAssets/*.*">
      <Link>%(Filename)%(Extension)</Link>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
  </ItemGroup>

  <!-- Snip ... -->

</Project>

Building the F# module

Clean up the old builds:

rm -fr ./psrepository
rm -fr ./out-module/fs-example

Dotnet-Build

And then build the module:

dotnet restore
dotnet build --configuration Release --output ./out-module/fs-example

Language locality bug

You have to use the en-US locale when publishing PowerShell modules.

$env:LANG = "en_US.UTF-8"
$env:LANGUAGE = "en_US.UTF-8"
$env:LC_MESSAGES = "en_US.utf8"

Installation

Remove old registered PowerShell repository:

try { Unregister-PSRepository -Name fs-example } catch { }

Register-PSRepository and Publish-Module

This quite complicated script will:

  • set up a PowerShell repository in current location,
  • register the PowerShell repository,
  • publish the module into the PowerShell repository,
  • install that published module from the PowerShell repository.
$repo = "fs-example"
$repoPath = "$pwd/psrepository/fs-example"

New-Item -ItemType Directory -Path $repoPath | Out-Null
Register-PSRepository -InstallationPolicy Trusted -Name $repo -SourceLocation $repoPath

Publish-Module -Verbose -Path $pwd/out-module/fs-example -Repository $repo
Install-Module -Scope CurrentUser -Force -Verbose -Name fs-example -Repository $repo

Removal

Uninstall-Module

Just call Uninstall-Module to remove any PowerShell module.

Uninstall-Module -Name fs-example

Usage in the REPL

Import-Module

Import it with Import-Module.

Import-Module -Verbose fs-example -Force

Finally - use Format-FsExample

Remember the above F# function that was defined in the class?

[<Cmdlet(VerbsCommon.Format, "FsExample")>]
type FsExample()

It will be now available under the name composed of the “common verb” and a secondary part, so Format-FsExample.

Try it:

Format-FsExample -Name Maciej

GHC 9.8 and Cabal 3.10.3 on Gentoo Linux

:: gentoo, haskell, programming language, system, tutorial

By: Maciej Barć

The official ::gentoo repository currently contains only GHC on version 9.2.8. To install newer GHC one has to either download/build themselves or use the ::haskell overlay (https://github.com/gentoo-haskell/gentoo-haskell).

Enable the ::haskell overlay

Enable:

eselect repository enable haskell

Sync:

emerge --sync haskell
egencache --update --repo haskell --jobs 12 --load 6
eix-update

Unmask needed packages

Add to /etc/portage/package.unmask/0000_hs.conf

<dev-lang/ghc-9.9

<dev-haskell/cabal-3.11
<dev-haskell/cabal-install-3.11
<dev-haskell/cabal-install-solver-3.11
<dev-haskell/cabal-syntax-3.11
<dev-haskell/text-2.2
<dev-haskell/parsec-3.1.18

Add to /etc/portage/package.accept_keywords/0000_hs.conf

app-admin/haskell-updater
dev-haskell/*
dev-lang/ghc

Install

emerge --ask --verbose ">=dev-lang/ghc-9.8" ">=dev-haskell/cabal-install-3.10"

Build of GHC 9.8 takes around ~2 hours on a 8-core laptop-grade CPU.

Bonus: masking packages from ::haskell

If you want to exclude a given version from the ::haskell overly from being installed/updated, then you can add a similar line(s) to /etc/portage/package.mask/0000_hs.conf:

app-emacs/haskell-mode::haskell

Comparing objects in Racket

:: lisp, programming language, racket, scheme, tutorial

By: Maciej Barć

Equality methods

By implementing a method for equality equal-to? and two extraction methods equal-hash-code-of and equal-secondary-hash-code-of we can define our own object comparison rules.

For more info see Object Equality and Hashing.

Consider the following example:

(define integer%
  (class* object% (equal<%>)
    (super-new)

    (init-field [value 0])

    (define/public (equal-to? other-object recur)
      (= value (get-field value other-object)))

    (define/public (equal-hash-code-of hash-code)
      (hash-code value))

    (define/public (equal-secondary-hash-code-of hash-code)
      (hash-code value))))

If we create a new integer% object we can notice that it is not transparent (we can not inspect values of any of it’s fields).

(new integer%)
;;  => (object:integer% ...)

But if we compare two fresh integer% objects they will be equal.

(equal? (new integer%) (new integer%))
;;  => #true

Transparent class

A transparent cvlass is a class with the inspect expression valuye se to #false.

From Racket documentation Creating Classes:

Just as for structure types, an inspector controls access to the class’s fields, including private fields, and also affects comparisons using equal?.

Consider the following example:

(define integer%
  (class object%

    (super-new)

    (inspect #false)

    (init-field [value 0])))

If we create a new integer% object we can see it’s field values.

(new integer%)
;;  => (object:integer% 0)

And if we compare two fresh integer% objects they will be equal.

(equal? (new integer%) (new integer%))
;;  => #true

Mkdocs with Scribble

:: racket, programming language, scribble

By: Maciej Barć

Intro

Instead of changing CSS style for Your Racket projects documentation, You may be interested in compiling Markdown files generated form Scribble source into HTML documentation website.

Creating MkDocs project

  1. Create docs directory and mkdocs.yml config file in current directory, along with a dummy index.md file in docs folder.

    mkdocs new .
  2. Edit the name of the project.

    Replace Racket-Project with your project name.

    ---
    site_name: Racket-Project

Building Scribble

Generate markdown files form scribble documentation.

Replace Racket-Project.scrbl with path to your scribble documentation main source file.

scribble --markdown --dest ./docs --dest-name index.md Racket-Project.scrbl

Building Markdown

Compile HTML documentation from the markdown source.

mkdocs build

HTML files should appear in the site directory.

Running the server

Some features, like search for example are only available when running the mkdocs server.

mkdocs serve

Caveats

Some scribble functions do not look good or work correctly for markdown-to-HTML compilation by MkDocs.

  • table-of-contents - looks like a source block

  • index-section - letter links do not work

Example configuration

site_name: Racket-Ebuild
site_author: xgqt@riseup.net
site_description: library to ease ebuild creation
site_url: https://gitlab.com/gentoo-racket/racket-ebuild

repo_name: gentoo-racket/racket-ebuild
repo_url: https://gitlab.com/gentoo-racket/racket-ebuild

plugins:
  - search

theme:
  name: material

extra:
  social:
    - icon: fontawesome/brands/gitlab
      link: https://gitlab.com/gentoo-racket/racket-ebuild

Awesome Racket language features

:: racket, programming language

By: Maciej Barć

Also see: Fast-Racket at Racket's GitHub Wiki

Creating binaries

You can create portable binaries with Racket's raco command! Use raco exe and raco distribute.

More -> https://docs.racket-lang.org/raco/exe.html

Sample games

Racket provides a executable plt-games, when ran (from console) it opens a menu of miscellaneous games, among them: jewel, minesweeper, aces, spider, checkers. & more (20 games total).

Plots

You can plot data in 2d & 3d forms.

2D

Sample code:

#lang racket/base
(require racket/gui/base racket/math plot)

(plot-new-window? #true)

(plot (function sin (- pi) pi #:label "y = sin(x)"))

3D

Sample code:

#lang racket/base
(require racket/gui/base racket/math plot)

(plot-new-window? #true)

(plot3d
 (surface3d (lambda (x y) (* (cos x) (sin y)))
            (- pi) pi (- pi) pi)
 #:title "An R × R → R function"
 #:x-label "x" #:y-label "y" #:z-label "cos(x) sin(y)")

Browser

There's a included library to render web pages, just "(require browser)".

Sample code:

#lang racket
(require browser)

(open-url "https://xgqt.gitlab.io/")

FFI

You can use Racket's Foreign Function Interface to interact with non-Racket libraries to make use of very fast libraries written in (mainly) FORTRAN & C.

For example sci uses FFI for CBLAS & LAPACK.

Parallelism

For greater speed up with parallel execution there are futures, places and distributed places (for distributed programming).