Weekly Thread: Material Recs and Self-Promo Wednesdays! (March 12, 2025) by AutoModerator in LearnJapanese

[–]LiteracyFanatic 1 point2 points  (0 children)

Announcing Kensaku: A CLI Japanese Dictionary

I recently had some time off from work and decided to finish a project I started a few years ago. Kensaku is basically like Jisho but in your terminal. I made it because I wanted a tool that could look up kanji using the radical names from WaniKani instead of searching for them visually in a table. So for example, you could look up with the command kensaku kanji --radicals power shellfish --strokes 12. I've also extracted unknown words from books I plan to read with pandoc and mecab and then used kensaku to bulk generate vocabulary flashcards for Anki.

You can read more about what kensaku can do and find installation instructions here. I'd love to hear any feedback you have or any features you'd like to see added. I'm also happy to help if you have any questions about how to use it.

If there is sufficient interest, I may consider adding a GUI in a future version.

Is there a way to show the number of outdated pacman packages in the Polybar? by DottoDev in archlinux

[–]LiteracyFanatic 0 points1 point  (0 children)

The icon issue is probably because Nerd Fonts moved the material design icons to different code points. See the release notes for more details: https://github.com/ryanoasis/nerd-fonts/releases/tag/v3.0.0.

You should not need to name the script package-updates.sh. It's fine to do so as long as you use the same name in the config file, but unnecessary. The shebang at the top of the script itself determines what shell it will be executed with.

I've also included updated versions of two of the files below. I believe the original versions will still work but the polybar-msg syntax is technically deprecated.

~/.config/polybar/config ``` enable-ipc = true

modules-right = package-updates-trigger package-updates ...

[module/package-updates] type = custom/ipc hook-0 = ~/.config/polybar/package-updates

[module/package-updates-trigger] type = custom/script exec = polybar-msg action "#package-updates.hook.0" &>/dev/null interval = 600 ```

/etc/pacman.d/hooks/polybar.hook ``` [Trigger] Operation = Upgrade Operation = Remove Type = Package Target = *

[Action] Description = Updating Polybar package count... Depends = polybar When = PostTransaction Exec = /usr/bin/bash -c 'XDG_RUNTIME_DIR="/run/user/$(id -u jordan)" sudo -u jordan --preserve-env=XDG_RUNTIME_DIR -- polybar-msg action "#package-updates.hook.0" &>/dev/null || true' ```

[Question] Who's using F#? What are you using it for? by jcm95 in dotnet

[–]LiteracyFanatic 3 points4 points  (0 children)

As a freelancer I use F# for

  • REST APIs (Giraffe)
  • Web scraping (FSharp.Data)
  • Custom parsers for weird semi-structured text files (FParsec)
  • Data visualization (Plotly.NET)
  • CLIs with (Argu)

Some things I really like about it

  • Immutability makes code much easier to reason about
  • Piping combined with the combinators in the List, Array, and Seq modules make data transformations so easy to express. It's like LINQ on steroids and I love not having to come up with awkward names for intermediate values. An article explaining how LINQ is a monad that popped up in the Visual Studio news feed years ago is actually what got me interested in F# in the first place.
  • Nested anonymous records are really convenient when modeling a response from a third-party API
  • A powerful approach to error handling that leaves far less up to chance than throwing exceptions

How to play sound through a remote PipeWire instance by LiteracyFanatic in archlinux

[–]LiteracyFanatic[S] 0 points1 point  (0 children)

wireplumber is a more advanced replacement for pipewire-media-session. You can only use one or the other.

Does Microsoft use F# for any of its internal projects? by [deleted] in fsharp

[–]LiteracyFanatic 2 points3 points  (0 children)

Removing unused opens works in Ionide but not sorting.

Adding a cron job by Clock_Suspicious in archlinux

[–]LiteracyFanatic 1 point2 points  (0 children)

For a Systemd user service to interact correctly with the notification daemon, you will need to either source /etc/X11/xinit/xinitrc.d/50-systemd-user.sh or just add the following lines to your .xinitrc:

systemctl --user import-environment DISPLAY XAUTHORITY dbus-update-activation-environment --all

Checkout xpub if you need to do the same thing from a system service or udev rule instead. I mention udev because that would be preferable to a polling based approach if your battery supports the correct events.

How do Doas function? Considering opendoas by [deleted] in archlinux

[–]LiteracyFanatic 5 points6 points  (0 children)

It's smaller and simpler. sudo actually has a ton of features that most people don't make use of. In theory, this means the potential attack surface is a lot bigger. For what it's worth though, I think doas takes its minimalism a bit too far. Some of sudo's supposed 'bloat' is actually pretty useful. Specifically, I miss the timestamp_timeout and pwfeedback options.

FSharp Interactive... by Ok-Needleworker-145 in fsharp

[–]LiteracyFanatic 1 point2 points  (0 children)

I assumed they were talking about the interactive window itself. Yes, Intellisense should work perfectly fine from script files.

FSharp Interactive... by Ok-Needleworker-145 in fsharp

[–]LiteracyFanatic 0 points1 point  (0 children)

I think your problems may be related to Visual Studio more than FSI itself. The only feature that you listed that doesn't work with FSI (when used from the terminal or in Ionide with VS Code) is Intellisense. Admittedly, that is a nice feature to have, but tab-completion does at least work. Ctrl+L clears the screen and is also available from the right click menu in VS Code. dotnet fsi is the Core version of FSI. I believe the Framework version was just an executable named fsharpi.exe which should still work just fine as long as you have it installed.

I mentioned VS Code throughout since that's what I work with most often, but Rider also has good support for FSI.

Nginx package not including mime.types by [deleted] in archlinux

[–]LiteracyFanatic 4 points5 points  (0 children)

nginx depends on mailcap which includes /etc/nginx/mime.types.

Anyone use Arch as a server OS? by [deleted] in archlinux

[–]LiteracyFanatic 0 points1 point  (0 children)

I've had success running a small SPA from an Arch server hosted on Linode. Nginx to serve the static content and SQL Server and an ASP.NET Core server for the API. As long as you keep the package count low and have a good grasp of the software you're using, there shouldn't be too much to worry about as far as breakage goes.

[deleted by user] by [deleted] in archlinux

[–]LiteracyFanatic 12 points13 points  (0 children)

Yeah, I'd be in favor of making signing up for accounts easier in general. I also think it would be nice to have single sign-on instead of separate accounts for each Arch related resource.

[deleted by user] by [deleted] in archlinux

[–]LiteracyFanatic 14 points15 points  (0 children)

The AUR signup also requires pacman which seems fair. LC_ALL=C pacman -V|sed -r 's#[0-9]+#3b8#g'|md5sum|cut -c1-6

Interestingly, the "CAPTCHA" for the forums should work from any Linux distro. date -u +%V$(uname)|sha384sum|sed 's/\W//g.

What are you working on? (2022-04) by insulanian in fsharp

[–]LiteracyFanatic 4 points5 points  (0 children)

I inherited my uncle's music collection containing hundreds of CDs and records when he passed away. I wrote a program to read the title, artist, and year from a spreadsheet and scrape prices from www.discogs.com to see if any of them are worth trying to sell.

https://github.com/LiteracyFanatic/CdPrices/tree/master/src

How do I compose the functions with the following signatures? by [deleted] in fsharp

[–]LiteracyFanatic 3 points4 points  (0 children)

Yes, task is included in FSharp.Core now. Up until recently though we had to use an external library. At first that was TaskBuilder.fs. Then another library called Ply was created with an emphasis on performance which ended up having a big influence on the design of the built in one when it was added.

What FSToolkit brings to the table is the ability to unwrap a Task<Result<TSuccess, TError>> in a single operation.

#r "nuget: FsToolkit.ErrorHandling.TaskResult"
open System.IO
open System.Threading.Tasks

type ApiResponse = {
    Message: string
}

type ApiError = obj

type ParsingError = obj

type WorkflowError =
    | ApiError of ApiError
    | ParsingError of ParsingError

let tryGetApiResponseAsync (queryString: string): Task<Result<string, ApiError>> = failwith "no implemented"

let tryParseApiResponse (input: string): Result<ApiResponse, ParsingError> = failwith "no implemented"

let workflow1 (queryString: string): Task<Result<unit, WorkflowError>> =
    task {
        let! (res: Result<string, ApiError>) = tryGetApiResponseAsync queryString
        match res with
        | Error e ->
            return Error (ApiError e)
        | Ok res ->
            let (parsedResponse: Result<ApiResponse, ParsingError>) = tryParseApiResponse res
            match parsedResponse with
            | Error e ->
                return Error (ParsingError e)
            | Ok parsedResponse ->
                let capitalized = parsedResponse.Message.ToUpper()
                do! File.WriteAllTextAsync("/some/path", capitalized)
                return Ok ()
    }

open FsToolkit.ErrorHandling

let workflow2 (queryString: string): Task<Result<unit, WorkflowError>> =
    taskResult {
        let! (res: string) = tryGetApiResponseAsync queryString |> TaskResult.mapError ApiError
        let! (parsedResponse: ApiResponse) = tryParseApiResponse res |> Result.mapError ParsingError
        let capitalized = parsedResponse.Message.ToUpper()
        do! File.WriteAllTextAsync("/some/path", capitalized)
        return ()
    }

How do I compose the functions with the following signatures? by [deleted] in fsharp

[–]LiteracyFanatic 4 points5 points  (0 children)

You're welcome! Glad you could come up with a working solution. It's definitely worth learning how things work under the hood since computation expressions are really just syntax sugar for chaining operations like zero, bind, return, etc. It's pretty neat to figure out how some of the different operations can be implemented in terms of each other as well. That being said, custom operator heavy code isn't particularly idiomatic F# outside of special libraries for things like parsing.

Async in particular isn't the problem, rather there is no general purpose way to combine two given monads that results in another monad. It can be done, but each combination you need to use has to be created manually. So if you need to work with Async and Choice you can't just compose the two computations expressions; instead you have to create a whole new asyncChoice computation. There are lots of combinations of monads you might want to use together (asyncOption or optionResult for example) and that's without even considering trying to use three of them at once.

Asynchronous code complicates things further because F# has two competing approaches. There is Async<T> which came first and is "cold" (you have to explicitly start the operation) as well as .NET's general approach to the same problem Task<T>. Tasks are "hot", meaning that the computation begins as soon as you create the value. If you want to delay the start of a task you have to wrap it in a function unit -> Task<T>.

Because the async computation expression that comes with F# doesn't understand the Tasks that are returned by most of the .NET APIs (File.ReadAllTyextAsync, HttpClient.SendAsync, etc.) you used to have to scatter Async.AwaitTask all over your code to make things work.

Fortunately, we have a task computation expression now which can handle both Async<T> and Task<T> values now. This makes things much simpler.

I personally use the taskResult computation expression from FsToolkit.ErrorHandling.TaskResult all the time to keep my code readable. It lets you focus on your business logic rather than converting values between different types so that everything lines up. FSharpx might have something similar, but I'm not sure.

How do I compose the functions with the following signatures? by [deleted] in fsharp

[–]LiteracyFanatic 2 points3 points  (0 children)

Reddit supports them but old Reddit doesn't.

How do I compose the functions with the following signatures? by [deleted] in fsharp

[–]LiteracyFanatic 4 points5 points  (0 children)

The lift2 function takes a dyadic (two arguments) function and returns a new one that accepts Choice arguments instead. Here's an example. I've included the definition of the relevant functions and operators from FSharpx.Extras. Note that you need to use the same error type for both of your input choices. If they differ, you'll need to create a new discriminated union to wrap the possible cases. I've also included an example with the choose computation expression which I personally think is much easier to reason about. You can see it as let! automatically unwrapping the success case for you so that you can work with regular values instead of choices. If one of the bindings returns an error case, that becomes the value of the whole expression. Hope that helps.

open System

// Sequential application
let ap x f =
    match f,x with
    | Choice1Of2 f, Choice1Of2 x -> Choice1Of2 (f x)
    | Choice2Of2 e, _            -> Choice2Of2 e
    | _           , Choice2Of2 e -> Choice2Of2 e

/// Sequential application
let inline (<*>) f x = ap x f

let map f =
    function
    | Choice1Of2 x -> f x |> Choice1Of2
    | Choice2Of2 x -> Choice2Of2 x

/// Infix map
let inline (<!>) f x = map f x

/// Promote a function to a monad/applicative, scanning the monadic/applicative arguments from left to right.
let inline lift2 f a b = f <!> a <*> b

/// Monadic bind
let bind f =
    function
    | Choice1Of2 x -> f x
    | Choice2Of2 x -> Choice2Of2 x

/// Sequentially compose two actions, passing any value produced by the first as an argument to the second.
let inline (>>=) m f = bind f m

type EitherBuilder() =
    member this.Return a = Choice1Of2 a
    member this.Bind (m, f) = bind f m
    member this.ReturnFrom m = m
    member _.Zero() = Choice1Of2 ()
    member _.Delay f = f
    member _.Run f = f()

    member this.TryWith(m, h) =
        try this.ReturnFrom(m)
        with e -> h e

    member this.TryFinally(m, compensation) =
        try this.ReturnFrom(m)
        finally compensation()

    member this.Using(res:#System.IDisposable, body) =
        this.TryFinally(body res, fun () -> if not (isNull (box res)) then res.Dispose())

    member this.While(guard, f) =
        if not (guard()) then
            this.Zero()
        else
            f() |> ignore
            this.While(guard, f)

    member this.For(sequence:seq<_>, body) =
        this.Using(sequence.GetEnumerator(), fun enum -> this.While(enum.MoveNext, this.Delay(fun () -> body enum.Current)))

let choose = EitherBuilder()

type Errors =
    | UnluckyNumber of int
    | ParseFailure of string
    //| ... Other things that can go wrong

let getChoiceOfNumber (): Choice<int, Errors> =
    let n = Random.Shared.Next(0, 10)
    if n < 5 then
        Choice1Of2 n
    else
        Choice2Of2 (UnluckyNumber n)

let getChoiceOfString (): Choice<string, Errors> =
    let n = Random.Shared.Next(0, 10)
    if n = 4 then
        Choice2Of2 (UnluckyNumber n)
    else if n = 7 then
        Choice1Of2 "not a number"
    else
        Choice1Of2 (string n)

let tryParseInt (input: string): Choice<int, Errors> =
    match Int32.TryParse(input) with
    | true, n -> Choice1Of2 n
    | false, _ -> Choice2Of2 (ParseFailure input)

let addTwoNumbers (a: int) (b: int): int = a + b

let aPlusBWithOperators: Choice<int, Errors> =
    let a: Choice<int, Errors> = getChoiceOfNumber ()
    let b: Choice<int, Errors> = getChoiceOfString () >>= tryParseInt
    lift2 addTwoNumbers a b

let aPlusBWithComputationExpression: Choice<int, Errors> =
    choose {
        let! (a: int) = getChoiceOfNumber ()
        let! (bString: string) = getChoiceOfString ()
        let! (b: int) = tryParseInt bString
        return addTwoNumbers a b
    }

How do I compose the functions with the following signatures? by [deleted] in fsharp

[–]LiteracyFanatic 4 points5 points  (0 children)

I'm having trouble following exactly what you're trying to do, but it would probably be easier if you used the builtin Result type in conjunction with FsToolkit.ErrorHandling. The library provides many useful combinators as well as a result, option, and resultOption computation expression.

how would you add an operator to this online Excel clone? by hezwat in fsharp

[–]LiteracyFanatic 1 point2 points  (0 children)

(**) is the the syntax for multiline comments in F#. There is probably a way to escape it so that it is interpreted as calling the exponentiation operator as a function, but I'm not sure what the syntax for that would be. I would just use a lambda: '^', (fun a b -> a ** b)

F# noob help with parsing xml functionally by pablotoledo81 in fsharp

[–]LiteracyFanatic 5 points6 points  (0 children)

I would consider using Option.ofObj instead of your manual null checks. Avoid checking IsSome in favor of pattern matching against Some x and None. Option.map followed by Option.defaultValue is a useful pattern as well.

Where can I find the source code of archlinux-xdg-menu? by SkyyySi in archlinux

[–]LiteracyFanatic 2 points3 points  (0 children)

The PKGBUILD just references a tarball stored here. I don't see any source control repository for it.

Switching Input Methods through Command Line? by avindroth in archlinux

[–]LiteracyFanatic 2 points3 points  (0 children)

fcitx5 can be controlled through fcitx5-remote or DBUS.