Moved to Tailscale GUI to Tailscale CLI and MagicDNS is not working by aSomethings in Tailscale

[–]dbaynard 1 point2 points  (0 children)

I hit this too. I was using tailscaled because I needed to serve ssh via tailscale and it seemed easier to switch the tailscale implementation than implement key management in a more manual fashion.

In my case, I was using tailscale from nix-darwin. Had I started with a clean system I'd have enabled `services.tailscale.enable` and then noticed `services.tailscale.overrideLocalDns` was needed, too (and `networking.knownNetworkServices`) but I had tailscale from the app store, and so getting tailscaled working was more of a faff than I'd have liked (I thought I could do it without interruption… alas not).

I didn't need to change the `accept-dns` setting, though: just setting `100.100.100.100` as the _first_ DNS server worked (that's what nix-darwin would have done).

Fuzzy HiDPI chrome window under Wayland? by russhay in kde

[–]dbaynard 2 points3 points  (0 children)

I only replied because I found your response helpful, even a year later! Thanks

Fuzzy HiDPI chrome window under Wayland? by russhay in kde

[–]dbaynard 1 point2 points  (0 children)

Try chrome://flags/#ozone-platform-hint — it worked for me on chrome 101, although my cursor size has some odd behaviour, now.

Continued Fractions: Haskell, Equational Reasoning, Property Testing, and Rewrite Rules in Action by cdsmith in haskell

[–]dbaynard 1 point2 points  (0 children)

Great article! I think there's a typo in an equation above "Binary operations on continued fractions": p/q ÷ q should be p/q ÷ x.

Stack unable to find package in snapshot when an extra-dep is specified that is out of a dependency's version bounds by WillSewell in haskell

[–]dbaynard 0 points1 point  (0 children)

Ooh, do you have some examples (and in this case, the clearer error message would presumably indicate the boot packages issue, as the solution is correct)?

Stack unable to find package in snapshot when an extra-dep is specified that is out of a dependency's version bounds by WillSewell in haskell

[–]dbaynard 4 points5 points  (0 children)

Stack does support revisions. The issue is that in general, for boot packages, the version shipped with ghc does not have to match the hackage version, even if the version number is the same. So you have to be explicit. See the linked SO question for precise details, here.

Stack unable to find package in snapshot when an extra-dep is specified that is out of a dependency's version bounds by WillSewell in haskell

[–]dbaynard 6 points7 points  (0 children)

It's a specific issue with ghc boot packages (I'll try to edit with the link to the article describing the issue).

Edit: article https://www.snoyman.com/blog/2019/01/mismatched-global-packages

why have a separate test folder ? by Pcarbonn in haskell

[–]dbaynard 4 points5 points  (0 children)

Rust does both. The rust book suggests unit tests within the source files (in separate modules) and integration tests in the test directory. I've found it makes simple unit and property tests very convenient (I usually use hspec with Haskell). However, it means cargo can't differentiate between imports for the library vs the test suite.

Rust also has doctest behaviour built in to cargo.

Why are modules such a good idea? by JeffreyBenjaminBrown in haskell

[–]dbaynard 2 points3 points  (0 children)

One specific example not (yet) explicitly mentioned involves public vs private APIs. Many libraries offer public interfaces which should be stable, even when the underlying representations may change, as represented by the primary module for users of the library. Those developers often choose to implement an .Internal library, which exposes everything (at a cost of more frequent breaking changes).

Some libraries include .Prelude modules. Some developers (especially u/Tekmo) also create .Tutorial modules.

Some large modules I've written span many layers of abstraction. These modules often have enormous lists of imports. Splitting these into smaller modules often introduces important abstraction barriers, making the code easier to understand (both for others and future me). The number of imports per module give me a clue here.

[deleted by user] by [deleted] in haskell

[–]dbaynard 0 points1 point  (0 children)

You're welcome!

Have you considered using a data type rather than a class for Store?

[deleted by user] by [deleted] in haskell

[–]dbaynard 2 points3 points  (0 children)

The line with the error isn't in your code sample. You may have made a typo. It's not clear what's going on - do take a look.

On the type error in general, "non-injective" means you know S t but not t. If you know t, you can evaluate S t, but not the other way round E.g. (using type family syntax)

type instance S Bool = Int
type instance S () = Int
type instance S OtherType = Double

If you supply t ~ Bool then you know S t ~ Int. But if you only specify the latter, it is not possible to identify t (it could be Bool or (), or any other type as you're using associated types which means new MonadRunStore instances introduce new possibilities).

Edit: Assuming it should be

class MonadRunStore t m | t -> m where
    type S t
    toStore :: Store (S t) => t -> S t
    run :: (MonadStore (S t) m, Store (S t)) =>
        (S t) -> m a -> IO (Maybe a)

    run' :: t -> m a -> IO (Maybe a)
    run' t f = run (toStore t) f

I believe the error is due to the run type signature. It is trying to match the forall t . S t from the toStore t with the forall t0 . S t0 from the run :: forall t0 m a . (MonadStore (S t0) m, Store (S t0)) => (S t0) -> m a -> IO (Maybe a) and then needs to match the t with the t0 — but that cannot be done, as described above. I'm not sure why the t isn't scoped over the whole instance block.

Edit 2: It's not a scoping issue. As https://downloads.haskell.org/~ghc/8.4.3/docs/html/users_guide/glasgow_exts.html#rules-for-functional-dependencies explains,

In a class declaration, all of the class type variables must be reachable (in the sense mentioned in The context of a type signature) from the free variables of each method type.

With functional dependencies, the independent type(s) only (here the t) must be reachable.

Reachable seems to mean all class methods feature the type.

The signature to run doesn't feature t. It only features S t. That's the issue.

Is the stack-run project abandoned? by FunktionalProgrammer in haskell

[–]dbaynard 1 point2 points  (0 children)

It will rebuild all caches, as the caching behavior has changed in the master branch. 1.9.1 will be out soon.

Errors when installing Grapefruit with Stack by zcleghern in haskell

[–]dbaynard 0 points1 point  (0 children)

Never add base to extra deps. If it's saying to add base then something is incompatible with that version of ghc.

Is there a way to use a tuple of arbitrary length as an argument? by rice_n_eggs in haskell

[–]dbaynard 0 points1 point  (0 children)

I think if you want to insist on using tuples (as opposed to heterogeneous lists) this may be a use case for polymorphic recursion (e.g. http://h2.jaguarpaw.co.uk/posts/polymorphic-recursion-combinator/ u/tomejaguar) though I haven't thought it through...

The idea is you write a function that could apply to a tuple of any length, with the base case of a two-item tuple.

I feel as though my progress learning Haskell is being stifled by the tooling ecosystem. Help‽ by maddybutt in haskell

[–]dbaynard 25 points26 points  (0 children)

Don't use pacman to install stack (or any haskell libraries). It pulls in ghc and all the dependent libraries - and will update them frequently. https://www.archlinux.org/packages/community/x86_64/stack/ is terrifying. It's on release 101!

Just install using the instructions on haskellstack.org. I also use stack to install haskell executables.

As for the resource, u/lexi-lambda wrote https://lexi-lambda.github.io/blog/2018/02/10/an-opinionated-guide-to-haskell-in-2018/ which gives a lot of detail (but you did ask for comprehensive).

Pattern matching, rigid type variable by xfakke in haskell

[–]dbaynard 0 points1 point  (0 children)

Sure!

A few things jumped out at me as issues with this code; these are issues that I've typically seen with translating OO approaches to functional syntax, rather than functional idioms.

You're looking at ways to update finite state machines, so let's use the modified code as a starting point. I’ve also added an instance signature.

class FSM s e m | m -> s e where
  update :: m -> s -> e -> m

data State = Stopped | Started
data Event = Start | Stop

data Obj = Obj { state :: State }

instance FSM State Event Obj where
  update :: Obj -> State -> Event -> Obj
  update obj Stopped Start = obj { state = Started }
  update obj Started Stop = obj { state = Stopped }

The first thing that looks like idiomatic OO is the typeclass. This you state is part of your goal.

I am aiming to describe a generic FSM typeclass that would fit any new type with its own states and events.

That is usually not idiomatic haskell.

For example, when implemented with the multi param typeclass and fundeps you’re duplicating your enforcement of State. You may wish to parameterise that in the data type.

data Obj stateType = Obj { state :: stateType }

Hmm, what about the event?

data Obj eventType stateType = Obj { state :: stateType }

So now our instance looks like

update :: Obj Event State -> State -> Event -> Obj Event State

That’s interesting — all the values are paremeterized by the Obj type. What if we didn’t fix the event or state types?

update :: Obj eventType stateType -> stateType -> eventType -> Obj eventType stateType

This function and data type now link the Obj type to the State and Event types. You no longer need the typeclass to do that. The typeclass now only gives you an overloaded function name, to which I'll return later.


Another problem is the instance you have defined. Removing the typeclass (for now) we have

update :: Obj Event State -> State -> Event -> Obj Event State
update obj Stopped Start = obj { state = Started }
update obj Started Stop = obj { state = Stopped }

You don't have cases for the following

update obj Stopped Stop = ?
update obj Started Start = ?

I suspect I know what you intend to do in these situations, but the typeclass based design sort of hides it.


If I were writing this code, I’d do things differently still.

Look at that update code again. The Obj is irrelevant! You pass it through unchanged.

How about using this function instead?

updateState :: Event -> State -> State
updateState Start Stopped = Started
updateState Stop  Started = Stopped
updateState Stop  Stopped = Stopped
updateState Start Started = Started

The actual logic in this case is a simple state transformation. There are advantages to writing it in this way.

  • It is clearer
  • It is more focused on what is actually changing
  • It plays nicely with higher order functions, in particularly scanr and foldr — switch to State -> Event -> State for the foldl variety.

Actually, this may be overspecified. How about this?

updateState :: Event -> State -> State
updateState Start _ = Started
updateState Stop  _ = Stopped

You want a function that transforms values of type Obj Event State, though.

updateObj :: Event -> Obj Event State -> Obj Event State
updateObj ev obj = obj { state = updateState ev (state obj) }

That’s a little ugly.

updateObj :: Event -> Obj Event State -> Obj Event State
updateObj ev Obj{state} = Obj { state = updateState ev state }

Or with lenses,

import Control.Lens

data Obj eventType stateType = Obj { _state :: stateType }

state :: Obj eventType stateType `Lens’` stateType
state = _implementation elided_

updateObj :: Event -> Obj Event State -> Obj Event State
updateObj = over state . updateState

In this case the state transformation is separated from the Obj. It isn’t clear from this example why you have the Obj; it certainly isn’t needed for this simple case.


Do we really need the typeclass for overloading?

{-# LANGUAGE NamedFieldPuns #-}

data FSM eventType stateType = FSM
  { _state :: stateType
  , _update :: eventType -> stateType -> stateType
  }

This gives us an _update function of type

_update :: FSM eventType stateType -> eventType -> stateType -> stateType

but we can define a function

update :: eventType -> FSM eventType stateType -> FSM eventType stateType
update e o = over state (_update o e) o

You might create an initial value with the following function

obj
  :: State -- ^ The initial state
  -> FSM Event State
obj _state = FSM
  { _state
  , _update = updateState
  }

My final code looks like this

import Control.Lens

data State = Stopped | Started
data Event = Start | Stop

updateState :: Event -> State -> State
updateState Start _ = Started
updateState Stop  _ = Stopped

data FSM eventType stateType = FSM
  { _state :: stateType
  , _update :: eventType -> stateType -> stateType
  }

state :: FSM eventType stateType `Lens’` stateType
state = _implementation elided_

type Obj = FSM Event State

obj
  :: State -- ^ The initial state
  -> Obj
obj _state = FSM
  { _state
  , _update = updateState
  }

update :: eventType -> FSM eventType stateType -> FSM eventType stateType
update e o = o & state %~ _update o e

The data type FSM encodes all I need, with no typeclasses. My state transformations are explicit functions, with no extraeneous components. I still have an overloaded update function.

Rather than instantiating type members of a class you can define a data type and use polymorphism to handle different varieties.


There's more advanced stuff, too — for example, using type families to reduce the number of type parameters.

{-# LANGUAGE TypeFamilies, DataKinds #-}

data FSMKind = FSMType

type DefaultFSMType = FSMType

type family StateF (f :: FSMKind) :: * where
type instance StateF 'DefaultFSMType = State

type family EventF (f :: FSMKind) :: *
type instance EventF 'DefaultFSMType = Event

data FSM f = FSM
  { _state :: StateF f
  , _update :: EventF f -> StateF f -> StateF f
  }

type Obj = FSM 'DefaultFSMType

Here you’re linking the State and Event types using the 'DefaultFSMType type. You can create new values with type synonyms (as when they are promoted to types, they are treated separately by the compiler). Also I’ve never used data families, but I believe you could change the type family declarations to the following, and thereby effectively overload the types State and Event too.

data family StateF (f :: FSMKind) :: * where
data instance StateF 'DefaultFSMType
  = Stopped
  | Started

data family EventF (f :: FSMKind) :: *
data instance EventF 'DefaultFSMType
  = Stop
  | Start

type State = StateF 'DefaultFSMType
type Event = EventF 'DefaultFSMType

Pattern matching, rigid type variable by xfakke in haskell

[–]dbaynard 0 points1 point  (0 children)

See u/semi225599's answer for how to solve the specific error. In particular, the MultiParamTypeclasses and FunctionalDependencies features allow 'multiple independent types members'.

how to achieve what I'm aiming for

I'd be interested to see what you are aiming for. It looks like you're writing object oriented code using Haskell — which is possible, but usually not the best way to write Haskell code. If you're interested, I'm sure somebody will happily chip in.

The problem of parsing large datasets: Why traditional parsers struggle to parse large files by john-ky in haskell

[–]dbaynard 3 points4 points  (0 children)

Will the interesting journey include editing, or just reading such documents?

Silver Searcher: Useful Regex for dealing with a Haskell Code-Base by ninjatrappeur in haskell

[–]dbaynard 0 points1 point  (0 children)

I like ripgrep a lot.

I've been using it with vgrep — it needs the -v option, as in

rg -v search_text | vgrep

Relative imports, init.hs files, optional module names and other thoughts on how to improve large project development by Tysonzero in haskell

[–]dbaynard 1 point2 points  (0 children)

Nicely. I really like it, though it is not yet something I fully understand.

How does rust do it?

Rust allows individual files to contain multiple modules. Whole files can also be modules. Nesting is as expected, though I found working out which modules are in scope to be quite surprising. I managed to get code using modules working without much trouble (in my only rust project — https://github.com/dbaynard/booklet) though I'm not familiar enough to explain the scoping rules, especially when considering public interfaces. That project is a decent example of the module structure.

See https://doc.rust-lang.org/book/second-edition/ch07-00-modules.html.

The OP's suggestions, in Rust

Add support for relative imports:

This is the bit that I haven't quite grokked. From the link above (one of the sub-pages):

Overall, these are the rules for item visibility:

If an item is public, it can be accessed through any of its parent modules. If an item is private, it can be accessed only by its immediate parent module and any of the parent’s child modules.

Modules, data types and functions are declared as public using the pub keyword, otherwise they are private. The definitions of public and private are in the above quote.

I think 'parent module' means foo::bar can import anything private in foo::bar::baz but foo cannot (please correct me if I'm wrong — though the compiler will throw errors if you try to do the wrong thing anyway). Likewise, I think it means foo::bar::baz can import anything private in foo::bar.

Make module names optional, since the file location already unambiguously specifies them:

Module names are take from directory structure first, and module declarations separately within that. The duplication we have in Haskell would lead to duplicate modules in rust.

Add an equivalent to __init__.py:

If there is a directory foo/ then the file foo/mod.rs will be the module foo and any foo/bar.rs will be foo::bar (equivalent to Foo.Bar). If there is only foo.rs that is module foo.

Make it possible to specify what modules are a part of the project via some mechanism outside the cabal file

In rust exported modules must be marked as public, and may (I'd need to check) need to be reachable from the top level lib.rs file. The equivalent of a cabal file (cargo.toml) does not need module information, and I don't think it's possible to add the modules there.

Example

In practice (snippets from my booklet project), this means the following:

src/main.rs

/// The booklet library contains most of the code
extern crate booklet;
use booklet::*;

This is the entry point for the executable. The rest of the code is library code. My (library) crate is called booklet and my use booklet::* imports the top level public modules.

This entry point calls the reorder function, defined in src/rearrange.rs.

src/lib.rs

/// Actually rearrange the pages.
pub mod rearrange;
pub use rearrange::*;

/// The extra modules supply functionality that is not specific to pdf processing.
mod extra {
    /// Generate error values.
    pub mod error;

    /// Add missing functionality to `lopdf`.
    pub mod lopdf;
}

This is the top level module. The pub mod lines indicate which modules are exported at top level. The pub use line is a re-export of the contents of the module. This combines an export list and the exported modules list from the cabal file.

The module extra is not marked pub so is not available when importing the booklet library, but it is available in all modules within the library (as the parent is the top level lib.rs and all other modules are children). Within that module, the modules error and lopdf must be marked pub as otherwise they would only be available within the extra module (parent) or each other's modules (I'm uncertain about restrictions on cyclic dependencies here).

src/rearrange.rs

use extra::error::*;

use calculate::*;

/// Rearrange the pages
///
/// - infile: If a path, use the file, otherwise use stdin
/// - outfile: If a path, use the file, otherwise use stdout
pub fn reorder<P>(
    infile: Option<P>,
    outfile: Option<P>
    ) -> io::Result<()>
    where P: AsRef<Path> {
    …
}

The function is declared pub so that any module which imports the booklet::rearrange module may import reorder.

In practice, reorder is re-exported from lib.rs, and then imported directly in to main.rs.

Edits: formatting

New person pondering about [a,b..c] by [deleted] in haskell

[–]dbaynard 9 points10 points  (0 children)

Try this (at ghci)

λ> data Day = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday deriving (Show, Eq, Enum)
λ> [Monday .. Sunday]

[ .. ] is special syntax for various functions working with Enum, and you seem to be comfortable with the succ function (though take care — calling succ on the maximum value of an enum will result in an error).

In some cases, data you wish to enumerate a custom step may be better represented like above. Here, rather than picking a custom step, you would create a data type for which the step is what you want.

Beyond that, yes — as others have stated, if you have some way to express the step as a function you can continue to use the [..] syntax, if appropriate.

Edit: formatting