new nix setup and fourmolu
This commit is contained in:
parent
b7b2e60331
commit
cfa75d1d38
6 changed files with 229 additions and 95 deletions
87
flake.lock
generated
87
flake.lock
generated
|
|
@ -1,42 +1,79 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"flake-parts": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
"nixpkgs-lib": "nixpkgs-lib"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1689068808,
|
||||
"narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
|
||||
"lastModified": 1712014858,
|
||||
"narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"rev": "9126214d0a59633752a136528f5f3b9aa8565b7d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"owner": "hercules-ci",
|
||||
"repo": "flake-parts",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"haskell-flake": {
|
||||
"locked": {
|
||||
"lastModified": 1713084600,
|
||||
"narHash": "sha256-qL7LV2MtwJ+1Xasg1TjSUmoE7yrRuXPqxpPlKjLE0SE=",
|
||||
"owner": "srid",
|
||||
"repo": "haskell-flake",
|
||||
"rev": "847292fc793a5c15c873e52e7751ee4267ef32a0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "srid",
|
||||
"repo": "haskell-flake",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1692210102,
|
||||
"narHash": "sha256-Th/csUBviIMpalVmRCbr2RUBT7OId6xEK9D0D7A589I=",
|
||||
"owner": "NixOS",
|
||||
"lastModified": 1712963716,
|
||||
"narHash": "sha256-WKm9CvgCldeIVvRz87iOMi8CFVB1apJlkUT4GGvA0iM=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "3514001703c39f37c854745d787911b48a48bc8e",
|
||||
"rev": "cfd6b5fc90b15709b780a5a1619695a88505a176",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs-lib": {
|
||||
"locked": {
|
||||
"dir": "lib",
|
||||
"lastModified": 1711703276,
|
||||
"narHash": "sha256-iMUFArF0WCatKK6RzfUJknjem0H9m4KgorO/p3Dopkk=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "d8fe5e6c92d0d190646fb9f1056741a229980089",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"dir": "lib",
|
||||
"owner": "NixOS",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
"flake-parts": "flake-parts",
|
||||
"haskell-flake": "haskell-flake",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"systems": "systems",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
|
|
@ -53,6 +90,26 @@
|
|||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1711963903,
|
||||
"narHash": "sha256-N3QDhoaX+paWXHbEXZapqd1r95mdshxToGowtjtYkGI=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "49dc4a92b02b8e68798abd99184f228243b6e3ac",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
|
|
|||
107
flake.nix
107
flake.nix
|
|
@ -1,43 +1,84 @@
|
|||
# SPDX-FileCopyrightText: 2021 Serokell <https://serokell.io/>
|
||||
#
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
{
|
||||
description = "My haskell application";
|
||||
|
||||
description = "srid/haskell-template: Nix template for Haskell projects";
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
systems.url = "github:nix-systems/default";
|
||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
||||
haskell-flake.url = "github:srid/haskell-flake";
|
||||
treefmt-nix.url = "github:numtide/treefmt-nix";
|
||||
treefmt-nix.inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = nixpkgs.legacyPackages.${system};
|
||||
outputs = inputs:
|
||||
inputs.flake-parts.lib.mkFlake { inherit inputs; } {
|
||||
systems = import inputs.systems;
|
||||
imports = [
|
||||
inputs.haskell-flake.flakeModule
|
||||
inputs.treefmt-nix.flakeModule
|
||||
];
|
||||
perSystem = { self', system, lib, config, pkgs, ... }: {
|
||||
# Our only Haskell project. You can have multiple projects, but this template
|
||||
# has only one.
|
||||
# See https://github.com/srid/haskell-flake/blob/master/example/flake.nix
|
||||
haskellProjects.default = {
|
||||
# The base package set (this value is the default)
|
||||
# basePackages = pkgs.haskellPackages;
|
||||
|
||||
haskellPackages = pkgs.haskellPackages;
|
||||
|
||||
jailbreakUnbreak = pkg:
|
||||
pkgs.haskell.lib.doJailbreak (pkg.overrideAttrs (_: { meta = { }; }));
|
||||
|
||||
# DON'T FORGET TO PUT YOUR PACKAGE NAME HERE, REMOVING `throw`
|
||||
packageName = "spell-checker";
|
||||
in {
|
||||
packages.${packageName} =
|
||||
haskellPackages.callCabal2nix packageName self rec {
|
||||
# Dependency overrides go here
|
||||
# Packages to add on top of `basePackages`
|
||||
packages = {
|
||||
# Add source or Hackage overrides here
|
||||
# (Local packages are added automatically)
|
||||
# https://github.com/lehins/hip.git
|
||||
# hip.source = inputs.hip + "/hip";
|
||||
};
|
||||
|
||||
packages.default = self.packages.${system}.${packageName};
|
||||
defaultPackage = self.packages.${system}.default;
|
||||
# Add your package overrides here
|
||||
settings = {
|
||||
# barbies-th = {
|
||||
# broken = false;
|
||||
# jailbreak = true;
|
||||
# };
|
||||
};
|
||||
|
||||
devShells.default = pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
haskellPackages.haskell-language-server # you must build it with your ghc to work
|
||||
cabal-install
|
||||
];
|
||||
inputsFrom = map (__getAttr "env") (__attrValues self.packages.${system});
|
||||
# Development shell configuration
|
||||
devShell = {
|
||||
hlsCheck.enable = true;
|
||||
};
|
||||
|
||||
# What should haskell-flake add to flake outputs?
|
||||
autoWire = [ "packages" "apps" "checks" ]; # Wire all but the devShell
|
||||
};
|
||||
devShell = self.devShells.${system}.default;
|
||||
});
|
||||
|
||||
# Auto formatters. This also adds a flake check to ensure that the
|
||||
# source tree was auto formatted.
|
||||
treefmt.config = {
|
||||
projectRootFile = "flake.nix";
|
||||
|
||||
programs.ormolu.enable = true;
|
||||
programs.nixpkgs-fmt.enable = true;
|
||||
programs.cabal-fmt.enable = true;
|
||||
programs.hlint.enable = true;
|
||||
|
||||
# We use fourmolu
|
||||
programs.ormolu.package = pkgs.haskellPackages.fourmolu;
|
||||
};
|
||||
|
||||
# Default package & app.
|
||||
packages.default = self'.packages.spell-checker;
|
||||
apps.default = self'.apps.spell-checker;
|
||||
|
||||
# Default shell.
|
||||
devShells.default = pkgs.mkShell {
|
||||
name = "haskell-template";
|
||||
meta.description = "Haskell development environment";
|
||||
# See https://zero-to-flakes.com/haskell-flake/devshell#composing-devshells
|
||||
inputsFrom = [
|
||||
config.haskellProjects.default.outputs.devShell
|
||||
config.treefmt.build.devShell
|
||||
];
|
||||
nativeBuildInputs = with pkgs; [
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,17 @@
|
|||
cabal-version: 3.0
|
||||
name: spell-checker
|
||||
version: 0.1.0.0
|
||||
-- synopsis:
|
||||
-- description:
|
||||
license: MIT
|
||||
license-file: LICENSE
|
||||
author: Jack Wines
|
||||
maintainer: jack@winesj.com
|
||||
-- copyright:
|
||||
category: Text
|
||||
build-type: Simple
|
||||
extra-doc-files: CHANGELOG.md
|
||||
-- extra-source-files:
|
||||
|
||||
common warnings
|
||||
ghc-options: -Wall
|
||||
|
||||
executable spell-checker
|
||||
import: warnings
|
||||
main-is: Main.hs
|
||||
other-modules: PrefixTree
|
||||
default-extensions: ScopedTypeVariables OverloadedStrings
|
||||
OverloadedLists TemplateHaskell DataKinds FlexibleContexts
|
||||
FlexibleInstances MultiParamTypeClasses OverloadedLabels
|
||||
|
|
@ -30,5 +23,5 @@ executable spell-checker
|
|||
text,
|
||||
MemoTrie
|
||||
|
||||
hs-source-dirs: src-exe
|
||||
hs-source-dirs: src
|
||||
default-language: GHC2021
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
{-# LANGUAGE OverloadedStrings #-}
|
||||
|
||||
module Main where
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Map.Lazy as M
|
||||
import qualified Data.List as L
|
||||
import qualified Data.Text.IO as TIO
|
||||
import qualified Data.Ord as O
|
||||
|
||||
|
||||
editDistance :: T.Text -> T.Text -> Word
|
||||
editDistance txt0' txt1' = memoMap M.! (txt0', txt1')
|
||||
where
|
||||
memoMap :: M.Map (T.Text, T.Text) Word
|
||||
memoMap = M.fromList . map (\txts -> (txts, uncurry editDistance' txts)) $ allPairs
|
||||
|
||||
allPairs = [(txt0'', txt1'') | txt0'' <- T.tails txt0', txt1'' <- T.tails txt1']
|
||||
|
||||
editDistance' txt0 txt1 = case (T.uncons txt0, T.uncons txt1) of
|
||||
(Nothing, Nothing) -> 0
|
||||
(Nothing, Just (_, txt)) -> succ . fromIntegral . T.length $ txt
|
||||
(Just (_, txt), Nothing) -> succ . fromIntegral . T.length $ txt
|
||||
(Just (x0, xs0), Just (x1, xs1)) -> (+) (if x0 == x1 then 0 else 1) $
|
||||
minimum . map (memoMap M.!) $ [
|
||||
(xs0, xs1),
|
||||
(txt0, xs1),
|
||||
(xs0, txt1)
|
||||
]
|
||||
|
||||
readDict :: IO [T.Text]
|
||||
readDict = T.lines <$> TIO.readFile "/usr/share/dict/words"
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
allWords <- readDict
|
||||
let word = "asoeunht"
|
||||
let vals = map (\x -> (x, editDistance word x)) allWords
|
||||
print $ L.minimumBy (O.comparing snd) vals
|
||||
39
src/Main.hs
Normal file
39
src/Main.hs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
module Main where
|
||||
|
||||
import Data.List qualified as L
|
||||
import Data.Map.Lazy qualified as M
|
||||
import Data.Ord qualified as O
|
||||
import Data.Text qualified as T
|
||||
import Data.Text.IO qualified as TIO
|
||||
import PrefixTree qualified as PT
|
||||
|
||||
editDistance :: T.Text -> T.Text -> Word
|
||||
editDistance txt0' txt1' = memoMap M.! (txt0', txt1')
|
||||
where
|
||||
memoMap :: M.Map (T.Text, T.Text) Word
|
||||
memoMap = M.fromList . map (\txts -> (txts, uncurry editDistance' txts)) $ allPairs
|
||||
|
||||
allPairs = [(txt0'', txt1'') | txt0'' <- T.tails txt0', txt1'' <- T.tails txt1']
|
||||
|
||||
editDistance' txt0 txt1 = case (T.uncons txt0, T.uncons txt1) of
|
||||
(Nothing, Nothing) -> 0
|
||||
(Nothing, Just (_, txt)) -> succ . fromIntegral . T.length $ txt
|
||||
(Just (_, txt), Nothing) -> succ . fromIntegral . T.length $ txt
|
||||
(Just (x0, xs0), Just (x1, xs1)) ->
|
||||
(+) (if x0 == x1 then 0 else 1)
|
||||
$ minimum
|
||||
. map (memoMap M.!)
|
||||
$ [ (xs0, xs1)
|
||||
, (txt0, xs1)
|
||||
, (xs0, txt1)
|
||||
]
|
||||
|
||||
readDict :: IO [T.Text]
|
||||
readDict = T.lines <$> TIO.readFile "/usr/share/dict/words"
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
allWords <- readDict
|
||||
let word = "supedpower"
|
||||
let vals = PT.fromList . map T.unpack $ allWords
|
||||
print $ PT.lookupClosest word vals
|
||||
42
src/PrefixTree.hs
Normal file
42
src/PrefixTree.hs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
module PrefixTree where
|
||||
|
||||
import Control.Applicative qualified as A
|
||||
import Data.Bifunctor qualified as Bi
|
||||
import Data.Foldable qualified as F
|
||||
import Data.List.NonEmpty qualified as NE
|
||||
import Data.Map.Strict qualified as M
|
||||
import Data.Maybe qualified as My
|
||||
import Data.Ord qualified as O
|
||||
|
||||
data Tree a = (Ord a) =>
|
||||
Tree
|
||||
{ isTermination :: Bool
|
||||
, children :: M.Map a (Tree a)
|
||||
}
|
||||
|
||||
empty :: (Ord a) => Tree a
|
||||
empty = Tree False M.empty
|
||||
|
||||
-- singleton :: (Ord a) => a -> Tree a
|
||||
-- singleton = Tree . flip M.singleton empty
|
||||
|
||||
fromList :: (Ord a, F.Foldable t) => t [a] -> Tree a
|
||||
fromList = F.foldl' insert empty
|
||||
|
||||
insert :: Tree a -> [a] -> Tree a
|
||||
insert (Tree{..}) [] = Tree{isTermination = True, ..}
|
||||
insert (Tree{..}) (x : xs) = Tree isTermination . flip (M.insert x) children . flip insert xs . My.fromMaybe empty . M.lookup x $ children
|
||||
|
||||
lookup :: (Ord a) => [a] -> Tree a -> Bool
|
||||
lookup [] = const True
|
||||
lookup (x : xs) = maybe False (PrefixTree.lookup xs) . M.lookup x . children
|
||||
|
||||
lookupClosest :: forall a. (Ord a) => [a] -> Tree a -> (Word, [a])
|
||||
lookupClosest [] (Tree True _) = (0, [])
|
||||
lookupClosest [] (Tree False _) = (0, [])
|
||||
lookupClosest (x : xs) (Tree{..}) = maybe rest (Bi.second (x :) . lookupClosest xs) $ M.lookup x children
|
||||
where
|
||||
rest :: (Word, [a])
|
||||
rest = Bi.first (+ 1) . F.maximumBy (O.comparing fst) . map charSkippedResult . M.assocs . M.delete x $ children
|
||||
|
||||
charSkippedResult (skippedChar, tree) = Bi.second (skippedChar :) . lookupClosest xs $ tree
|
||||
Loading…
Add table
Add a link
Reference in a new issue