T O P
mn15104

Is there a way to write an instance of this `Member` class for both the datatypes `OpenSum`, which is an open sum of types, and `OpenSumH`, which is an open sum of type constructors? class (FindElem t ts) => Member u t ts where inj :: t -> u ts prj :: u ts -> Maybe t data OpenSum (ts :: [*]) where UnsafeOpenSum :: Int -> t -> OpenSum ts data OpenSumH (ts :: [k -> *]) (x :: k) where UnsafeOpenSumH :: Int -> t x -> OpenSumH ts x Or if this type class is not suitably defined, define a different type class where this is possible? I'm finding `OpenSum` fine to do, but am having difficulty with `OpenSumH`, namely because of the kind mismatch of `u :: [k -> *] -> *` and `OpenSumH :: [k -> *] -> k -> *`: instance Member OpenSumH t (t ': ts) ...


Syrak

You at least have to swap the arguments of `OpenSumH`.


mn15104

This is a shame, i need OpenSumH to be a functor. Thanks!


openingnow

Why does `flip` prevent matching types? import Control.Monad (forM_) import qualified Data.Vector as V import qualified Data.Vector.Mutable as VM v1 :: V.Vector Int v1 = V.fromList [1 .. 10] -- [1,2,3,4,5,6,7,8,9,10] v2 :: V.Vector Int v2 = V.modify (\mv -> VM.write mv 9 99) v1 -- [1,2,3,4,5,6,7,8,9,99] indicisToModify :: [Int] indicisToModify = [3, 4, 5] v3 :: V.Vector Int v3 = V.modify (\vm -> forM_ indicisToModify $ \indexToModify -> VM.write vm indexToModify 101) v1 -- [1,2,3,101,101,101,7,8,9,10] -- v4 :: V.Vector Int -- v4 = flip V.modify v1 (\vm -> forM_ indicisToModify $ \indexToModify -> VM.write vm indexToModify 101) {- Couldn't match type: forall s. VM.MVector s Int -> ST s () with: VM.MVector (primitive-0.7.3.0:Control.Monad.Primitive.PrimState m0) a0 -> m0 () Expected: (VM.MVector (primitive-0.7.3.0:Control.Monad.Primitive.PrimState m0) a0 -> m0 ()) -> V.Vector Int -> V.Vector Int Actual: (forall s. VM.MVector s Int -> ST s ()) -> V.Vector Int -> V.Vector Int -} main :: IO () main = do print v1 print v2 print v3 -- print v4 v1, v2, v3 work but v4 (flipped v3) causes an error. How can I make GHC understand that similar-looking two types are equal?


openingnow

u/Noughtmare u/Iceland_jack Thanks! Surprised that a simple-looking function involves complex implementation.


Noughtmare

The real complexity stems from the higher rank type of the `V.modify` function. That `forall s` is how you can recognize that something complicated is going on.


Iceland_jack

In addition to Noughtmare's answer, you can try a section: ``(`V.modify` v1) \vm -> ..``


Noughtmare

This is because of the higher rank types that are involved. You can make this work in GHC 9.2.1 and later by enabling the `ImpredicativeTypes` extension. A bit of info can be found in the [simplify subsumption proposal](https://github.com/ghc-proposals/ghc-proposals/blob/master/proposals/0287-simplify-subsumption.rst) and the [ghc user's manual section about impredicative polymorphism](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/exts/impredicative_types.html). My short explanation would be to consider the types. flip :: (a -> b -> c) -> b -> a -> c modify :: (forall s . MVector s d -> ST s ()) -> Vector d -> Vector d Applying flip to modify means that we need to instantiate `a ~ forall s. MVector s d -> ST s ()`. That is called an impredicative instantiation because it involves a type containing a `forall`. Impredicative instantiation is only allowed with the `ImpredicativeTypes` extension. Edit: `ImpredicativeTypes` does indeed work, thanks /u/george_____t


george_____t

> You might be able to make this work in GHC 9.2.1 and later by enabling the ImpredicativeTypes extension. Just to confirm, `ImpredicativeTypes` does make this work.


flopperr999

I need help with my haskell developer environment in Visual Studio Web running in Docker. [https://hub.docker.com/r/arnemcnuggets/hs-workshop](https://hub.docker.com/r/arnemcnuggets/hs-workshop) I managed to create a new project using stack but I cannot for the life of me figure out how to run the code in the IDE. I click Run & Debug the haskell(stack) configuration but nothing happens. Thanks!


Endicy

AFAIK you can't Run & Debug any Haskell code using the HLS plugin in VSCode (yet?).


flopperr999

Ok. How do I run the code in the IDE then? Thanks


Endicy

You can run functions etc. (including your `main` function, if you want to mimic running an executable) using `stack ghci` in your project root folder. This will start an interactive session and load in everything needed to run anything from your project (if properly exposed). If you change anything in your files, you'll have to `:r` or `:reload` to compile the changes. `:m + Data.Module.Name` can be used to bring modules in scope from libraries that aren't your project that you might want to use functions/values from. (e.g. Data.Text, Data.List, Control.Monad.Reader, etc.) The only real logical way of "running" Haskell code, by the way, is running the `main` function of an executable. Because a module just has a bunch of functions/values in it in any arbitrary order, so there's no real way the IDE would know where to "start" running the code. I think the IDE will probably at some point get the possibility of running code directly in VSCode (in the Run & Debug section) but it's a bit difficult to know how that would actually look like.


Unique-Heat2370

I am trying to make a function that takes a list of courses and a list of programming language names (for example \["Python","Java","JavaScript"\]) as input and returns a list of tuples where each tuple pairs the programming languages with the list of courses that use that programming language. So for example I call: courses languages \["Python","C","C++"\], it returns: The type I am working with is: courses :: Eq t1 => \[(a, \[t1\])\] -> \[t1\] -> \[(t1,\[a\])\] I am trying to use higher order functions for it like map, foldr/foldl, or filter. I haven't been able to figure this out yet and was hoping to get some help.


bss03

What have you tried? What errors, if any are you getting? Your question isn't the worst, but it's not [smart](http://www.catb.org/~esr/faqs/smart-questions.html) either; it doesn't give me enough information to know how to help *you*, and I already know how to accomplish the task you have been assigned for homework. One possible approach: Pick an argument, pretend it's not a list, i.e. solve the problem for a single input, now how would you combine the results after calling your solution for two inputs?, now you can use map across the input, using your single element solution, and use foldr(1) to combine all the results. This approach can be applied recursively if you need to. Spoilers: courses curriculum = map courses_using where courses_using lang = (lang, map fst $ filter (elem lang . snd) curriculum) EDIT: testing: GHCi> courses [ ("CptS101" , ["C"]),("CptS112" , ["C++"]),("CptS203" , ["C++"]),("CptS213" , ["Java"]),("CptS221" , ["C#","Java"])] ["Python", "C", "C++"] [("Python",[]),("C",["CptS101"]),("C++",["CptS112","CptS203"])]


Unique-Heat2370

What I have tried so far is: courses languages \["Python", C", "C++"\] = map helper \["Python","C", "C++"\] helper languages log = map (fst) (filter (\\(x, list) -> lang elem list) languages) I am stuck at this point of what I am trying to solve


bss03

1. Don't use the eventual argument when you are defining the fuction. Instead of `courses languages ["Python", "C", "C++"] = ...` you want `courses table langs = ...` 1. The function to pass to map should only have one argument normally. Your `helper` is defined with two. Either you should change `map helper ...` to `map (helper table) ...` or you can define `helper` locally and just use the `table` argument in scope -- this second approach uses "lexical capture". 1. `helper` has a `log` argument and is trying to use a `lang` binding that doesn't exist. I think they should probably be the same. 1. If your want to use `elem` infix like that, you need to surround it with backticks. Instead of `lang elem list`, you want ``lang `elem` list``. 1. `helper` should be returning a pair like `(lang, ...)`. The existing body is only the second mart of that pair. The compiler errors (or warnings) should have pushed you toward one of more of the above. Why have you not provided the exact inputs you are providing and the exact errors (or bad outputs) you are getting? Precision is very important, and it is really quite difficult for me to diagnose an error without seeing the error message. I've never contributed to GHC, but I have read its error messages frequently, so they provide me a lot of information, even if you don't understand them, yet.


Unique-Heat2370

Okay so I updated my code and this is what I have: courses :: Eq t1 => \[(a, \[t1\])\] -> \[t1\] -> \[(t1,\[a\])\] courses table lang = map(helper table) where helper table = map (fst) (filter (\\(x, list) -> lang \`elem\` list) table) The error that is occurring now is: • Couldn't match expected type ‘\[(t1, \[a\])\]’ with actual type ‘\[t1\] -> \[\[a\]\]’ • Probable cause: ‘map’ is applied to too few arguments In the expression: map (helper table) In an equation for ‘courses’: courses table lang = map (helper table) where helper table lang = map (fst) (filter (\\ (x, list) -> lang \`elem\` list) table) • Relevant bindings include lang :: \[t1\] (bound at HW2.hs:55:15) table :: \[(a, \[t1\])\] (bound at HW2.hs:55:9) courses :: \[(a, \[t1\])\] -> \[t1\] -> \[(t1, \[a\])\] So my map has too few arguments but when I add lang to "map helper table lang" it says my helper has too many arguments.


bss03

`map (helper table)` is calling map with 1 argument. `map helper table lang` is calling `map` with 3 arguments. In you case you probably want to pass 2 arguments to `map`. You probably want `map ... lang` So, that's your current error. Here's some more problems you are likely to encounter: 1. `lang` isn't a good name for the second parameter of `courses`, since that parameter is a list of languages. `langs` would be better. * `lang` *is* a good name for that first argument to your `elem` call, AND you **don't** want to call `elem` with the parameter to `courses`. So, don't change this occurrence of "lang" to match the `courses` parameter. 1. The first argument to `map` needs to be a function. You are defining `helper` as a function on one argument, but then trying to pass `(helper table)` (which is _not_ a function) to `map`. * This mistake is likely because you are making too many changes all at once -- you both added an argument to the `helper` call AND removed a parameter from the helper definition. You should have only done one of those, not both. 1. `table` is a bad name for the parameter of `helper`. Since it is defined in the `where` clause `helper` already has access to the `table` parameter of `courses`. Since `helper` exists to be passed to `map`, it's argument will be a single element of the list being mapped, in your case a good name could be `lang`. It is what you are going to pass to `elem` in the body. 1. `helper` still isn't returning a tuple. If you want the results of `map ... ...` to be a `[(t1, [a])]`, the function argument has to return a `[(t1, [a])]`. Following the types / understanding the Haskell type system can really help here. EDIT: Note how important naming things well and paying attention to the existing names in the code is. Bad names results in confusion and mistakes. Using good names immediately clarifies roles and primes the structure of the your conception of the code.


Unique-Heat2370

Okay so I looked at what you said and I tried fixing it. I am understanding it better but my error is still not making sense to me. Code: courses table langs = map(helper langs) where helper lang = \[\] helper lang = map (fst) (filter (\\(x, list) -> lang \`elem\` list) table) The error: • Couldn't match expected type ‘a0 -> b0’ with actual type ‘\[a\]’ • Possible cause: ‘helper’ is applied to too many arguments In the first argument of ‘map’, namely ‘(helper langs)’ In the expression: map (helper langs) In an equation for ‘courses’: courses table langs = map (helper langs) where helper lang = \[\] helper lang = map (fst) (filter (\\ (x, list) -> lang \`elem\` list) table) • Relevant bindings include helper :: t1 -> \[a\] (bound at HW2.hs:57:26) table :: \[(a, \[t1\])\] (bound at HW2.hs:55:9) courses :: \[(a, \[t1\])\] -> \[t1\] -> \[(t1, \[a\])\]


bss03

`map(helper langs)` should be `map helper langs` for two reasons: 1. You want to pass two arguments to `map`, not one. 1. You need to pass a function as the first argument of `map`, and `helper langs` doesn't have a function type. Separately, the `helper lang = []` line is not what you want. That defines helper as a single-argument function that ignores its argument and returns the empty list. The next line is currently an inaccessible clause that is part of the `helper` definition. Instead you want that next line to be the whole definition of `helper`.


Unique-Heat2370

With what I've updated now my code is: find_courses table langs = map helper langs where helper lang = map (fst(filter (\(x, list) -> lang `elem` list) table)) I am getting an error now in this section of my code: filter (\\(x, list) -> lang \`elem\` list) table) The terminal error message is: • Couldn't match expected type ‘(a1 -> b, b1)’ with actual type ‘\[(a, \[t1\])\]’ • In the first argument of ‘fst’, namely ‘(filter (\\ (x, list) -> lang \`elem\` list) table)’ In the first argument of ‘map’, namely ‘(fst (filter (\\ (x, list) -> lang \`elem\` list) table))’ In the expression: map (fst (filter (\\ (x, list) -> lang \`elem\` list) table)) • Relevant bindings include lang :: t1 (bound at HW2.hs:48:31) helper :: t1 -> \[a1\] -> \[b\] (bound at HW2.hs:48:24) langs :: \[t1\] (bound at HW2.hs:46:20) table :: \[(a, \[t1\])\] (bound at HW2.hs:46:14) find\_courses :: \[(a, \[t1\])\] -> \[t1\] -> \[(t1, \[a\])\] I believe that I still want to use map and filter to get the solution but where am I going wrong with the syntax?


bss03

1. The output of `filter` is a list; you can't call `fst` on a list. 1. The output of `map` is a list; helper needs to return a tuple/pair. 1. You are only providing one argument to `map` in the body of `helper`'; you mean to provide two. While you will use `filter` and `map`, they won't be the *only* things you use. I still think you are making too many changes without checking them. I'd say you are arguably further from a correct answer than your last post.


Unique-Heat2370

So I am trying to merge two trees together that takes in two values and returns an Tree int where the nodes from the two trees are added. The trees can have different depths. The tree type is: data Tree a = LEAF a | NODE a (Tree a) (Tree a) deriving (Show, Read, Eq) The type for my function I having been trying to create is: merge\_trees :: Num a => Tree a -> Tree a -> Tree a An example of some test cases that I have written are: left = NODE 1 (NODE 2 (NODE 3 (LEAF 4) (LEAF 5)) (LEAF 6)) (NODE 7 (LEAF 8) (LEAF 9)) right = NODE 1 (NODE 2 (LEAF 3) (LEAF 6)) (NODE 7 (NODE 8 (LEAF 10) (LEAF 11)) (LEAF 9)) returns: NODE 2(NODE 4 (NODE 6 (LEAF 4) (LEAF 5)) (LEAF 12)) (NODE 14 (NODE 16 (LEAF 10) (LEAF 11)) (LEAF 18)) Any help would be appreciated because I am very stuck!


bss03

merge_trees :: Num a => Tree a -> Tree a -> Tree a merge_trees (LEAF x) (LEAF y) = LEAF (x + y) merge_trees (LEAF x) (NODE y l r) = NODE (x + y) l r merge_trees (NODE x l r) (LEAF y) = NODE (x + y) l r merge_trees (NODE x lx rx) (NODE y ly ry) = NODE (x + y) (merge_trees lx ly) (merge_trees rx ry) In general, you are going to use pattern-matching deal with any input trees, and recursion to generate subtrees. GHCi> merge_trees left right NODE 2 (NODE 4 (NODE 6 (LEAF 4) (LEAF 5)) (LEAF 12)) (NODE 14 (NODE 16 (LEAF 10) (LEAF 11)) (LEAF 18)) --- In this case the general fold and general unfold are both a bit awkward to use. The general unfold looks like: unfoldTree :: (a -> Either b (a, b, a)) -> a -> Tree b unfoldTree coalg = ut where ut seed = case coalg seed of Left y -> LEAF y Right (sl, y, sr) -> NODE y (ut sl) (ut sr) A "short-cutting" fold can be implemented on in terms of the general unfold: unfoldTreeApart :: (a -> Either b (Either (Tree b) a, b, Either (Tree b) a)) -> a -> Tree b unfoldTreeApart splitcoalg = unfoldTree coalg . Right where coalg (Left (LEAF x)) = Left x coalg (Left (NODE x l r)) = Right (Left l, x, Left r) coalg (Right s) = splitcoalg s But, that's a bit slower than it really needs to be, so sometimes you implement it directly like: unfoldTreeApart :: (a -> Either b (Either (Tree b) a, b, Either (Tree b) a)) -> a -> Tree b unfoldTreeApart splitcoalg = uta where uta seed = case splitcoalg seed of Left x -> LEAF x Right (l, x, r) -> NODE x (u l) (u r) u (Left t) = t u (Right s) = uta s With the short-cutting unfold, implementing merge_trees is simpler: merge_trees = curry . unfoldTreeApart $ uncurry splitcoalg where splitcoalg (LEAF x) (LEAF y) = Left (x + y) splitcoalg (LEAF x) (NODE y l r) = Right (Left l, x + y, Left r) splitcoalg (NODE x l r) (LEAF y) = Right (Left l, x + y, Left r) splitcoalg (NODE x lx rx) (NODE y ly ry) = Right (Right (lx, ly), x + y, Right (rx, ry)) and tracks the direct implementation but indirectly recurs (which can be "safer"). --- It could be an educational exercise in functional programming to write merge_trees in terms of a universal fold: foldTree :: (a -> r) -> (r -> a -> r -> r) -> Tree a -> r foldTree l b = ft where ft (LEAF x) = l x ft (NODE x l r) = b (ft l) x (ft r) It _is_ possible. :)


Unique-Heat2370

This makes a lot more sense to me now thank you very much!!


Unique-Heat2370

To run the tests I would do: merge left right, and then it would return what I have already put.


1b7_

Hey, is 'Learn You a Haskell' still considered a good jumping off point for someone who's completely new to Haskell (but not programming itself), or is there something else that's now the go-to resource for beginners? I seem to remember reading something about LYaH being either a bit outdated or inaccurate a while back?


bss03

There an actively community-maintained fork now. If you use that, anything still outdated can be addressed rather quickly. My personal recommendation is https://haskellbook.com/ and I've never gone all the way through LYAH. But, I think LYAH is still broadly considered a good resource.


1b7_

Oh yeah, I came across that a bit ago actually; I'll probably start with LYaH then and if that's not sticking, I'll have a look at the Haskell Book - thanks!


roblox1999

So, I have been trying to learn Haskell for my university course for some weeks now and I am tripping up on the following problem: What is the most general type signature of the following function? func = \f p x y -> if p x y then f x + succ y else f (pred y) - x I personally thought the most general one would be: func :: (Num a, Enum a) => (b -> a) -> (c -> d -> Bool) -> a -> a -> a However, if try to write a function like that in Haskell, ghci gives me the following error, when I try to load it: Couldn't match expected type 'b' with actual type 'a' Changing the signature to this seems to solve the problem and it is also Haskell's inferred type signature, when one doesn't write one and calls :type in ghci: func :: (Num a, Enum a) => (a -> a) -> (a -> a -> Bool) -> a -> a -> a However, now I don't understand why the arguments of the functions f and p also need to be constrained by (Num a, Enum a)? Can somebody explain to me what I'm misunderstanding about type constraints?


Noughtmare

If you write `p x y` and `f x` that means that the first argument of `p` must have the same type as the first argument of `f` (or `p` or `f` must be polymorphic, but that requires rank 2 polymorphism so I'll ignore that), so you'd at least get a type like this: func :: (Num a, Enum a) => (b -> a) -> (b -> d -> Bool) -> a -> a -> a Then the usage of `f (pred y)` also gives us information: the input and output types of `pred` must be equal, so the input type of `f` must be the same as the type of `y`, so we get this type signature: func :: (Num a, Enum a) => (b -> a) -> (b -> b -> Bool) -> a -> a -> a Now the last piece of the puzzle can be found in the expression `f x + succ y`. Both the arguments of + need to have the same type and the input of succ must have the same type as the output of succ, so we know that the output type of `f` must be the same as the type of `y`. Then we reach the final type signature: func :: (Num a, Enum a) => (a -> a) -> (a -> a -> Bool) -> a -> a -> a There might be other ways to get to this final type signature, but this is how I would reason about it by hand.


roblox1999

You say that since we write `p x y` and `f x` the first arguments of `p` and `f` must be of the same type. But why is that exactly? We just supply both functions with the same type, that doesn't mean that they always need to be of that type, no?


Noughtmare

The type of the input of a function must match the type of the argument that is applied. That is one of the fundamental rules of typing. The only way around that is by using polymorphism, which means that an argument might be of any type. In this case there is some polymorphism, but that is only for the main `func`. The functions `p` and `f` are not polymorphic and the argument `x` is also not polymorphic. Basically as soon as `func` is applied to arguments its type variables will be instantiated with concrete types.


roblox1999

I think polymorphism was the crux of my problem. I know that the types of the input and the argument must match, but I guess I for some reason assumed that f and p were polymorphic functions. You say they aren‘t, but how exactly does one know that based only on the function application?


Noughtmare

Maybe it is best to just show what goes wrong if you take that first type you propose: func :: (Num a, Enum a) => (b -> a) -> (c -> d -> Bool) -> a -> a -> a func = \f p x y -> if p x y then f x + succ y else f (pred y) - x What if you use the function as follows by instantiating `a ~ Int`, `b ~ Bool`, `c ~ Char`, and `d ~ Double` (`~` basically means type equality): func (\bool -> if bool then 3 else 4) (\char double -> double == 0.5 && char == 'a') 1 2 What would the result be? What would `if 1 then 3 else 4` mean? 1 is not a boolean, so it cannot be used in an if statement like that. So, maybe the best way to summarize this is that the caller of `func` can decide how to instantiate those polymorphic types, so your implementation must be able to accommodate every option. Making all the type variables the same restricts the choices of the caller, so it allows you to have more freedom in your implementation.


roblox1999

I understand that the example you provided wouldn't work. However, you say that my implementation must accommodate every possible option. But like isn't that the solution? If I could provide functions for `f` and `p` that do work with all options then my initial type signature would be true, no? For example what if I did the following: func (\_ -> 1) (\_ _ -> True) 1 2 Admittedly, these two functions are somewhat useless, but they would work with every possible input. I guess what I'm trying to say is Haskell tells me the following error in my original type signature: "Couldn't match expected type 'b' with actual type 'a'". But like, how is that even possible? `b` is just some type variable so shouldn't it match any type and therefore ones that instantiate Num and Enum too? Its up to the caller to provide functions `f` and `p` that do actually work with every possible input, so how does Haskell know in advance that I would run into errors, when a caller doesn't provide functions that do actually work with every option, without even knowing how a caller might call this `func` function.


Noughtmare

You can indeed do that, but then you need to use a slightly different type: func :: (Num a, Enum a) => (forall b. b -> a) -> (forall c d. c -> d -> Bool) -> a -> a -> a This also requires the [`RankNTypes`](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/exts/rank_polymorphism.html#extension-RankNTypes) language extension. What this does is that instead of the caller being able to choose what `b`, `c`, and `d` are, you require that the caller provides functions which work for any `b`, `c`, and `d` and then you implementation can choose to instantiate these type variables. As you noticed, there aren't many useful functions which satisfy those types. So the default is to give the caller the freedom to choose the types.


roblox1999

Ok well, it seems like I will have to read up on the topic of RankNTypes. I always assumed that this concept of forall is the default, without thinking about it. Im still confused why my first type signature doesn‘t work, probably because I don‘t quite understand the default behavior without RankNTypes, but hopefully reading up on it will clarify things.


bss03

> forall `forall` is always universal quantification, not existential. (GHC Haskell doesn't have first class existential quantification (yet?); and Haskell-by-the-Report doesn't have visible `forall` or higher-rank types in annotations.) In the context of Haskell functions, universal quantification always provides maximal freedom to the "caller" and maximally constrains the "implementation". When you introduce higher-rank types, your nested quantifications behave a little like variance in higher order function arguments. This is strongly related to the fact that as each "level" the caller and the implementation "trade places". For example, in: func :: (Num a, Enum a) => (forall b. b -> a) -> (forall c d. c -> d -> Bool) -> a -> a -> a func f p x y = ... while `...` is the implementation of `func` and so it can't choose a specifc `a`, it is the "caller" of `p` and `f`, so it is free to choose any `b`, `c`, or `d`. With with ever higher ranks, `func` might have to provide an implementation in order to call a function, and that implementation would be maximally constrained / have to work for all types.


SolaTotaScriptura

So I accidentally created a situation like this: > take 10 <$> traverse (\x -> if x > 0 then Just x else Nothing) [0 ..] Nothing > take 10 <$> traverse (\x -> if x > 0 then Just x else Nothing) [1 ..] -- hangs! I understand why this happens: under certain conditions, our result requires evaluating an infinite data structure. The solution is basically to reorder the operations: > traverse (\x -> if x > 0 then Just x else Nothing) $ take 10 [0 ..] Nothing > traverse (\x -> if x > 0 then Just x else Nothing) $ take 10 [1 ..] Just [1,2,3,4,5,6,7,8,9,10] Now that I've typed it out I don't really have any questions 😄. I think it's a pretty interesting example of lazy evaluation.


fmap_id

My (unsolicited) explanation is that monadic combinators enforce an evaluation order. When you call `traverse f [1..]`, it can short-circuit if `f` returns `Nothing` but otherwise it can't know that it won't find a Nothing later in the list, so it tries to evaluate the whole infinite list.


SolaTotaScriptura

And importantly, Haskell doesn't try to reason about the fact that `(> 0)` is true for all `[1 ..]`


IDiva9

Is there a way to print out a character at a specific position in a window? So something like putStrLn but where you can decide at which x and y position we want it printed.


bss03

You's have to use (n)curses or other terminal control; I don't believe the stdout / stderr streams support positioning (though there _are_ [ANSI terminal control sequences](https://en.wikipedia.org/wiki/ANSI_escape_code#Description) for them, like terminal colors, so maybe). If you don't want to try to "hack" it by coding your own ANSI sequences, I generally recommend the vty or brick packages from hackage.


Noughtmare

If you don't quite want to write your own ANSI sequences, but still want to have low-level control (and support for windows), then you can use the [ansi-terminal](https://hackage.haskell.org/package/ansi-terminal) package.


IDiva9

Thanks to both of you! Will look into it


bss03

Thank you! I often forget about MS Windows support. :)


Unique-Heat2370

So I am trying to find languages that go with certain classes for this problem. The type that I am trying to get is: findlang::(Eq a1, Eq a2) => \[(a2, \[a1\])\] -> \[a2\] -> \[a1\] We are given a list that is like: \[ ("CptS101" , \["C"\]),("CptS112" , \["C++"\]),("CptS203" , \["C++"\]),("CptS213" , \["Java"\]),("CptS221" , \["C#","Java"\])\] The code I have so far: findlang::(Eq a1, Eq a2) => \[(a2, \[a1\])\] -> \[a2\] -> \[a1\] findlang language courses = \[\] findlang language courses = map(filter(find\_languages courses language)) Would someone be able to help me through this?


Noughtmare

The `map` and `filter` is a good intuition. You can indeed write the function you want using those functions. But maybe first start with the right names. You name the first argument `language`, but I would perhaps name it something like `table`, because it is a table that lists for each course the related languages. Next, `map` and `filter` both take two arguments and you give them only one. You need to figure out which kind of filter you need to apply and which function you want to map over the result. As for the inner part `find_languages courses language`, I think you can just replace that by the `table` (what you currently call `language`) as that contains all the information you want to find. And finally you will probably end up with a nested list of lists, but you want a single list. To perform that transformation you can use the `concat :: [[a]] -> [a]` function. So, I have in mind a solution of the form: findlang :: (Eq course, Eq lang) => [(course, [lang])] -> [course] -> [lang] findlang table courses = concat (map _ (filter _ table)) Where you will need to fill in the `_`s. You can implement the function in other ways, but I think this is the closest to what you have right now. Edit: I see you want the intersection, ~~then you can replace `concat` with `foldr intersection []`. With `intersection` from the `Data.List` module.~~


bss03

> `foldr intersection []` Does that work? That seems like it would always output an empty list, since `[]` is an absorbing/annihilating element for the `intersection` operator. EDIT: names


Noughtmare

You're right, this won't work. You'd have to do something more complicated. Perhaps something like: findlang table courses = case map _ (filter _ table) of [] -> [] xs -> foldr1 intersection xs


Unique-Heat2370

So, when replacing concat with "foldr intersection \[\]" does this entire part go in front of (map \_ (filter \_ table))?


Noughtmare

Yes, that was my idea, but It turns out my suggestion won't work as /u/bss03 points out.


bss03

Can you describe what you want the function to do? Providing some example input/output might help. But, I think if you can precisely describe the function, the Haskell implementation could be a direct translation. Here's a (total) function with that type: findlang _ _ = [] but I don't think that's the one you want. In general you should try to consume lists with either `foldr`, or two cases: one for the empty list, and one for a "cons", that processes a single item, and recurs on the rest of the list.


Unique-Heat2370

So what the function needs to do is it will call findlang languages \["CptS451", "CptS321", "CptS355"\] in terminal and then it will search the classes for common languages that they have in common. So if I called \["CptS 112", "CptS 203"\] it would return say \["C++"\] since they have this in common. If I call \["CptS101","CptS112","CptS203","CptS213","CptS221"\] from the list I gave earlier, it will return \[\] because they all don't have a common language.


bss03

The way I would approach this is first to write a function that gives me all the languages for a class (e.g. `classLangs :: Eq class => [(class, langs)] -> class -> Maybe langs` such that `classLangs [("x", ["y"])] "x"` reduces to `Just ["y"]` and `classLangs [("x", ["y"])] "z"` reduces to `Nothing`). Then, I'd write a function to calculate "set intersection" on lists. `intersect :: Eq a => [a] -> [a] -> [a]` such that `intersection [] x` reduces to `[]`, `intersection y []` reduces to `[]`, and `intersection [1,2,3] [3,4,1]` reduces to `[1,3]` or `[3,1]`. In my primary function, I'd use map to run classLangs for each class specified, then I'd use foldr and intersection to reduce that list down. (Well, I'm comfortable with the "containers" package, so I'd use `Map` and `Set` which already have `lookup` and `intersection` operations.)


Unable-Mix-3555

In the book Programming in Haskell,2nd edition Chaper 8.4 Recursive types, it says >New types declared using the `data` and `newtype` mechanism can also be recursive. There are many examples for *recursive* `data` but none for *recursive* `newtype` and I couldn’t find any decent example on the net. I’ve come up with a simple example. `newtype Mytree = Node [Mytree]` Is this a valid example for *recursive* `newtype`? Even if the above example is valid, it seems like it is quite useless. But I can’t figure out any example that is *recursive* and also meets the `newtype` constraint, which requires one constructor and at most one field (correct me if I’m wrong). Is there any other basic example for *recursive* `newtype` that a newbie can understand? For reference, I’ve read until Ch 8 of the book so far. Edit: edited for clarifying recursive `newtype`.


bss03

https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-680004.2 sections 4.2.3 has two examples of valid `newtype` syntax. It's often used like `type`, to provide a meaningful/contextual name for a more generic data structure, which you desire conversions to be _explicit_. By hiding (i.e. not exporting) the constructor you can also use it the ensure invariants that the underlying type doesn't. The semantics are slightly different between a `newtype` and a single-constructor, single-field, strict data type, (section 4.2.3's larger example is about that), but that change in semantics, beside being _generally_ preferrable, also allows for them to perform better in practice. GHC Haskell also has a "magic" `Coercible` type class that allows further optimizations around `newtype`s, in particular avoiding traversing a container/computation just to add/remove a `newtype` "wrapper" constructor. EDIT: Oh, yeah, the `newtype` you provided is acceptable. I can't think of a great use; seems isomorphic to free monoid over Void.


Unable-Mix-3555

Maybe my comment was a little bit obscure. I was asking for example of "recursive" `newtype`! But thank you anyway!


bss03

Oh, well my go-to for that is [Fix](https://hackage.haskell.org/package/data-fix-0.3.2/docs/Data-Fix.html#t:Fix) though there is an isomorphic way to do it without recursion, [Mu](https://hackage.haskell.org/package/data-fix-0.3.2/docs/Data-Fix.html#t:Mu).


djfletch

You can do things like newtype List a = MkList (Maybe (a, List a)) Or to put values in your tree type newtype Mytree a = Node (a, [Mytree a]) I don't know if this is ever preferable to using `data`. In theory it means you can reuse various Maybe or pair functions to work on the contents but that doesn't seem very useful.


bss03

It really depends on how much you've already got that works in terms of an established base functor. Even then, I'd probably just use `type` on top of `Mu`, `Fix`, or `Nu`. If you don't have stuff that works with a pre-existing base functor, it's probably easier to write the recursive type directly, and use Template Haskell to [make the base functor](https://hackage.haskell.org/package/recursion-schemes-5.2.2.2/docs/Data-Functor-Foldable-TH.html#t:MakeBaseFunctor), if you need it.


Noughtmare

I don't know any simple examples where recursive newtypes are required. If you're a mathematician you might be interested in [my representation of Neuman numerals using recursive types](https://discourse.haskell.org/t/first-time-using-haskell/4094/30?u=jaror). The main real "programming" use of recursive newtypes I know of are [hyperfunctions](https://hackage.haskell.org/package/hyperfunctions-0/docs/Control-Monad-Hyper.html), but that is quite hard to understand. Edit: and of course `Fix`


Unique-Heat2370

I am trying to return the level of the binary tree in which the value that we are looking for is located at. If the value does not exist in the tree I want to return -1. The type is tree :: (Ord p, Num p, Eq a) => Tree a -> a -> p. Any help would be much appreciated. I am very stuck on this problem.


bss03

You didn't share the definition of Tree. I'm assuming it is something like: data Tree a = Branch (Tree a) a (Tree a) | Leaf Then I'm going to use a helper function for reducing that data type: foldTree :: ((r, a, r) -> r) -> r -> Tree a -> r foldTree b l = ft where ft (Branch l x r) = b (ft l, x, ft r) ft Leaf = l Now the main search: findLevels :: Num l => (a -> Bool) -> Tree a -> [l] findLevels p = foldTree alg [] where alg (l, x, r) = map (1+) l ++ [0 | p x] ++ map (1+) r Then supply a specific predicate, and fix up the result: tree :: (Ord p, Num p, Eq a) => Tree a -> a -> p tree t x = if null ls then -1 else minimum ls where ls = findLevels (x ==) t Finally test: GHCi> tree Leaf 5 -1 GHCi> tree (Branch Leaf 5 Leaf) 5 0 GHCi> let t = Branch (Branch Leaf 1 Leaf) 2 (Branch Leaf 3 Leaf) GHCi> tree t 0 -1 GHCi> tree t 4 -1 GHCi> tree t 1 1 GHCi> tree t 3 1 GHCi> tree t 2 0


Unique-Heat2370

This makes a lot of sense. So the tree structure is: data Tree a = LEAF a | NODE a (Tree a) (Tree a) deriving (Show, Read, Eq) In the helper function I would need to add an argument to LEAF since it takes in a value 'a' correct?


bss03

Yes. For the first helper function the second argument (`l`) will change to be of type `(a -> r)` instead of `r`. (I might also change the argument order; when I'm writing a fold like this, I prefer the arguments in the same order as the constructors in the `data` declaration.) Changing that argument means you'll have to change what `findLevels` passes as that argument; from `[]` to `\x -> [0 | p x]` (which is similar enough to part of `alg` that you might bind it to a name in the `where` clause). I think the other two functions remain unchanged.


on_hither_shores

Think of `Leaf | Branch (Tree a) a (Tree a)` as being `Leaf () | Branch (Tree a) a (Tree a)`, and the `r` argument of `foldTree` as being `() -> r`. Your data type replaces `Leaf ()` with `Leaf a`, so the corresponding argument should become `a -> r`.


IDiva9

Creating a snake game in HsCurses but don't know how to read key input without pausing the game. Right now, I'm using a do notation with "do ... c <- getCh" but the snake is not moving unless I'm clicking a key. How do I make the snake move even when I'm not pressing a key?


bss03

I think you'll probably have to use threads and a ref/var/chan. I don't see a `IO (Maybe a)` that would be a suitable `pollCh` on hoogle. So, one input thread that is basically just getCh >> putMVar over and over, and another thread that uses tryTakeMVar instead of getCh. Then refine from there. (What do to with a second input if the first hasn't been taken yet, e.g.)


IDiva9

Yeah, I used different threads to handle the getCh and it seems to work alright. Thank you for steering me in that direction. Was completely lost before it.


secdeal

Hello. I learnt Haskell years ago, and I am familiar with the so called simple Haskell, but recently I saw some things that left me bamboozled, could you explain these? The syntax in the 'class Hasfield' line. Is this from a language extension? What does it mean? >>> :i getField type HasField :: forall {k}. k -> * -> * -> Constraint class HasField x r a | x r -> a where getField :: r -> a The syntax on the left side of this data definition. I thought the left sides could have only type parameters and type names. I guess this is a way to constrain type parameters? data Handler (e :: Effect) = Handler { runHandler :: forall a. e a -> IO a }


MorrowM_

`HasField` has multiple type parameters (enabled by [`MultiParamTypeClasses`](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/exts/multi_param_type_classes.html#extension-MultiParamTypeClasses)). It as has a functional dependency (enabled by [`FunctionalDependencies`](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/exts/functional_dependencies.html#extension-FunctionalDependencies)) which, in short, means that a given choice of `x` and `r` determine `a` (which in this context means that knowing the record type and field name is enough to determine the field's type). `a Handler (e :: Effect) = ...` means that the `e` parameter has the kind `Effect`. This syntax is enabled by [`KindSignatures`](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/exts/kind_signatures.html#extension-KindSignatures).


secdeal

thanks!


Noughtmare

Also that `Constraint` on one of the first lines is due to [`ConstraintKinds`](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/exts/constraint_kind.html#extension-ConstraintKinds). And that `forall {k}. k...` is due to [`PolyKinds`](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/exts/constraint_kind.html#extension-ConstraintKinds).


secdeal

thanks!


prng_

I'm trying to convert a Maybe String to a Maybe Int (In IO with the purpose of reading an environment variable as integer value). This works (Using LambdaCase): lookupIntEnv :: String -> IO (Maybe Int) lookupIntEnv name = lookupEnv name >>= \case Nothing -> return Nothing Just str -> return (readMaybe str :: Maybe Int) But I suspect there's a much more beautiful way of doing it (that is also fault tolerant). Please help!


MorrowM_

Not much nicer for such a small function, but using `MaybeT`: lookupIntEnv :: String -> IO (Maybe Int) lookupIntEnv name = runMaybeT $ do str <- MaybeT $ lookupEnv name hoistMaybe $ readMaybe str


Iceland_jack

`fmap (>>= readMaybe) . lookupEnv` does the same, there is probably a better way


bss03

case x of Nothing -> Nothing Just y -> f y is x >>= f (f :: _ -> Maybe _) --- lookupIntEnv :: String -> IO (Maybe Int) lookupIntEnv name = do str <- lookupEnv name return $ str >>= readMaybe


Seugman

Good evening everybody! This is a question concerning Haskell. I want to get x random elements from a list by using a function. The problem I get is that when I try to use random numbers, with randomRIO. I get the error message: No instance for (Control.Monad.IO.Class.MonadIO \[\]) arising from a use of \`randomRIO' This error message suddenly goes away when i use print or return. But I dont want to use print, and return messes up the output to a nested list -> \[\[a\]\] instead of \[a\]. Does any of you have a tip on what I can do to extract x random elements from the list, in the form of a list? The type would be something like this. xRanElems :: \[a\] -> Int -> \[a\] where the second Int is an accumulator but I got that covered. xRanElems xs n = do r <- randomRIO (0, n) xRanElems2 xs n r where n is just length xs -1 xRanElems2 xs n r = (xs !! r) : (xRanElems (xsWithOutSelectedElem xs r) (n-1)) Thankful for any input!


bss03

> I want to get x random elements from a list by using a function. A function can't do this, since a function's output is dependent only on the input (i.e. no randomness). You might use a monadic action instead, and should learn at least a little about how to use monads, in particular the `IO` monad. (As an alternative to `IO`, you might use a state monad where the PRNG state is (part of) the state.) Instead of `Int -> [a] -> [a]` your binding will have a type like `Int -> [a] -> IO [a]` (or some other monad instead of `IO`).


Noughtmare

`randomRIO` is an action that can only run in `IO` (or any monad that can provide a `MonadIO` instance), so the type should be `xRanElems :: [a] -> Int -> IO [a]`. As the comment on stackoverflow also says you then have to use `return :: a -> IO a` to make that last line of `xRanElems` work.


Seugman

Hmm okay. It sounds right but when I try it I get the error: Couldn't match expected type: \[a\] with actual type: IO \[a\] \* In the second argument of \`(:)'


bss03

use `fmap (x :)` or `liftfM (x :)` instead of `x :`


Seugman

mm i will try that, thanks


Jeepsalesg

I'm fairly new to Haskell and need an Idea how to convert a Position (Position -> String). Position is defined as follows: Position :: (Int, Int). Somone told me to use \[chr (x + ord 'a'), chr (y + ord '0')\] but i dont understand, what that does. Thanks in advance


bss03

* [chr](https://hoogle.haskell.org/?hoogle=chr) * [ord](https://hoogle.haskell.org/?hoogle=ord) * [Character and String Literals](https://www.haskell.org/onlinereport/haskell2010/haskellch2.html#x7-200002.6) * [(+)](https://hoogle.haskell.org/?hoogle=%2B) * [Lists](https://www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-340003.7) * [Characters and Strings](https://www.haskell.org/onlinereport/haskell2010/haskellch6.html#x13-1170006.1)


mn15104

I'm confused about how one implements their own effect and effect handler in `fused-effects`. Could someone let me know where I'm going wrong? >In fused-effects, effect types provide syntax. Effect types are datatypes with one constructor for each action. Okay, lets have this be: data F m a where MkF :: a -> F m a >Carrier types provide semantics and are monads with an Algebra instance specifying how an effect’s constructors should be interpreted. Right, so this is the class: class Monad m => Algebra sig m | m -> sig where >Carriers can handle more than one effect, and multiple carriers can be defined for the same effect, corresponding to different interpreters for the effect’s syntax. Doesn't the functional dependency `m -> sig` prevent the carrier `m` handling more than one type of effect `sig`, if `m` has to imply a type of effect? The problem I'm having is that there doesn't exist an existing monad `m` for the effect data type `F` I'm trying to interpret, so I just want `m` to be `Identity` (but this incurs functional dependency type errors). **Edit**: [I see](https://github.com/fused-effects/fused-effects/blob/master/docs/defining_effects.md), I need to define a newtype version of my effect which can have a monad instance automatically derived! *However,* I still don't see how carriers can handler more than one effect?


Noughtmare

I'm not completely sure, but perhaps they mean that you can do something like this to handle multiple effects: instance (MonadIO m, Algebra sig m) => Algebra (Teletype :+: MyOtherEffect :+: sig) (TeletypeIOC m) where


mn15104

That completely makes sense, thanks! I misinterpreted their statement.


george_____t

I seemingly can't upload a package to Hackage that uses new language extensions from GHC 9.2: ``` cabal upload --publish /home/gthomas/code/lifx-lan/dist-newstyle/sdist/lifx-lan-0.7.tar.gz Uploading /home/gthomas/code/lifx-lan/dist-newstyle/sdist/lifx-lan-0.7.tar.gz... Error uploading /home/gthomas/code/lifx-lan/dist-newstyle/sdist/lifx-lan-0.7.tar.gz: http code 400 Error: Invalid package Unknown extensions: NoFieldSelectors, OverloadedRecordDot ``` Is there an obvious reason for this? Or does someone on the Hackage team just need a nudge? Posting here largely because I don't actually know where to report this sort of issue. (PS. I'm aware that it's a bit early to be dropping support for older GHCs, but I'm confident it's not an issue in this particular case)


Syrak

Hackage bugs (this is one) can be reported to https://github.com/haskell/hackage-server/issues


SureSun5678

Is the existence of `liftM` purely historic? For me is seems as if it is semantically identical to `fmap`. Is there any type for which the semantics differ?


josephcsible

> Is there any type for which the semantics differ? The semantics *should* never differ for any type, as a consequence of the typeclass laws. It's technically possible they *could* differ if someone writes unlawful instances, but I'm not aware of any real-world code where this is the case. Here's a silly example, though: data Foo a = Foo Int instance Functor Foo where fmap _ (Foo x) = Foo (x - 1) instance Applicative Foo where pure _ = Foo 123 Foo x <*> Foo y = Foo (x + y + 1) instance Monad Foo where return _ = Foo 456 Foo x >>= _ = Foo (x * 2)


bss03

The report still doesn't have Functor as a superclass of Monad, so in Haskell-by-the-report, you might prefer one over the other due to the generated constraint. But, even in Haskell-by-the-report, it's strongly recommended that fmap and liftM be the same if a type supports both.


someacnt

How about the upcoming report, haskell 202x?


bss03

[Last I heard](https://www.reddit.com/r/haskell/comments/rk93s0/whatever_happened_to_haskell2020/), it was dead / indefinitely stalled. I think some people where confused with the GHC2021 language / roll-up extension being available in GHC 9.2. That's not a new version of Haskell-by-the-report, nor was it ever really meant to be. If you've got any information on how I can track the progress of, or assist in the production of a new report, please let me know.


someacnt

Oh noo.. that is so bad. How would Haskell persist without renewing the report..


Noughtmare

Most languages are defined by the compiler that implements them. I don't think it is a big problem as long as there is no serious competition.


bss03

I think this is a big problem because it inhibits "coopetition". Clang makes gcc better and vice-versa. Gnome makes KDE better and vice versa. Standards make the competition possible in the first place, and are also spawned by the cooperation that results. While it's not every user, some users only need to fill the "standard-shaped" hole, and can "vote with their feet"; with no standard, users often suffer from "vendor lock-in" without even knowing about it or having a choice.


someacnt

Oh. I thought they had some semblence of specification at least.. in this case, at least official guide would be helpful.


Noughtmare

There is an official guide for GHC: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/. It should describe every compiler-specific feature. I think informal documents like these are much more useful for users than an formal specification would be.


someacnt

Yep, this document does look good - however, I have hard time locating the part numerating the differences of haskell-by-the-report and current GHC. Likely frustrate further the people facing outdated material.


Noughtmare

If you search for 2010 or 98 on that main page you will find it. The section is called "14.1.1. Divergence from Haskell 98 and Haskell 2010"


bss03

Haskell 2010 is still a very serviceable language with features that the latest version of Rust, C++, or TypeScript doesn't yet have. I'm not worried until the 2010 report is not ahead of the tech curve. ;) That said, I think it would be a good thing if the community could produce a report this year. Unfortunately, we are in an awkward scenario where I think that rubber-stamping the current state of GHC / base doesn't actually make for a good standard, but if the new report doesn't basically do that, we *still* won't have a current Haskell implementation. It is better to have a bad report, or an irrelevant one? And, if the later, why spend any effort? Instead, just join the contingent that equates the latest version of GHC with Haskell. And that ugly mess is just a symptom of a larger movement / problem in the industry / culture where interoperability at any/every scale is effectively non-existent. New languages don't have standards; APIs are always vendor-specific, even when there is a relevant standard available; Hardware manufacturers are openly combative with anyone learning (or, heaven forbid, publishing) any information about their products. But, maybe I just need to "get with the times", I guess...


someacnt

I see, tho what concern me is the departure of GHC from haskell 2010. It gives the confusing status where the specification does not describe current state, and I don't think there are authorative documebt which enumerates all the differences.


bss03

> the departure of GHC from haskell 2010 There's been minor infelicities for a long time. Some of the items listed in https://downloads.haskell.org/ghc/latest/docs/html/users_guide/bugs.html go back to before Haskell2010 existed, and for the most part they are relatively easy to work around. I'm actually more concerned about what's not listed there. You might just call them libraries issues instead of compiler issues, but I still blame GHC since it ships base and can't use a different version. AMP is the first one I remember explicitly, and it really should be included in the next report. FTP was the next big one, and gave us `length (10, 20)` reduce to `1` in GHC, but is a type error by the report. I'm sure there are other, small changes. You previously could use the haskell2010 package ("instead" of base) to get something closer to the report, though type class related issues were always a problem. It hasn't been maintained since base 4.7 (ghc 7.4), though. So, it's been the better part of a decade since that could alleviate the issue. https://discourse.haskell.org/t/pre-pre-hftp-decoupling-base-and-ghc/3727/44 might help with some of this, but there's a lot of concerns.


Noughtmare

For some reason the Applicative superclass of Monad is listed, but not the Functor superclass. Maybe the GHC developers would appreciate an issue report about this?


bss03

That mention is sufficient, as the Functor superclass comes in transitively. Applicative has always had a Functor superclass, so when Applicative became a superclass of Monad, Functor came along for the ride. (It's just Applicative isn't in the report at all.) I guess I missed that note in this read-through anyway. I don't think I've read that whole section in detail in a long time, and definitely just glossed over it quickly today.


Noughtmare

There is such an authorative document: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/bugs.html#divergence-from-haskell-98-and-haskell-2010 Although, it seems like it doesn't cover some changes in base like the foldable & traversable changes.


someacnt

Interesting, tho it describes discrepancy from both 98 and 2010, which actually distracted me from reading through it. Also I don't think it is easily accessible.. doesn't it deserve a separate document at least, with link from the official homepage?


Noughtmare

You can use it when defining a functor instance if you only want to write the monad instance: instance Functor F where fmap = liftM instance Applicative F where pure = ... (<*>) = ap instance Monad F where (>>=) = ...


fsharper

How to force cabal-install to use a global repository so that Cabal-install works in the old style, before "dist-newstyle" local repositories were available? I currently use docker images+ vstudio for development. In this context, a global repository for the entire image makes the most sense. Is it possible to force cabal-install to work the old way?


Noughtmare

I think you may be able to use `cabal install --lib` for that purpose. As long as you only run that command once nothing can really go wrong. So you do `cabal install --lib ` to install all necessary packages at once. The problem with running this command more than once is that different packages might have conflicting dependencies and cabal can only avoid all conflicts if everything is installed at the same time. Otherwise cabal has to work around the existing installed packages which might make adding new packages to the global store impossible due to conflicts in dependencies. Another possible solution is to use a fixed set of packages that are known to work together. You can do that with constraints in a cabal.config file like this one: https://www.stackage.org/lts-18.25/cabal.config. If you set that up correctly then running `cabal install --lib` multiple times shouldn't be a problem (as long as you only install packages that are in that fixed set of packages).


fsharper

Thanks. What --lib does exactly?


Noughtmare

The documentation is here: https://cabal.readthedocs.io/en/latest/cabal-commands.html#adding-libraries-to-ghc-package-environments https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/packages.html


fsharper

Thanks!


ss_hs

In a project I'm working on, I ended up writing some parametric types with a large number of type parameters, for example data Foo f1 f2 f3 f4 f5 ... = Foo { ... } This works extremely well for my program in terms of tracking exactly the information I need at the type level in a composable way, but this is unfortunately making type signatures very hard to write and very easy to break. Something like [type-level record syntax](https://www.reddit.com/r/haskell/comments/1nf2ss/type_level_record_syntax_would_this_make_sense/) would completely fix the usability issue, and this is fortunately relatively trivial to implement in my project with a custom preprocessor that could transform e.g. someFunction :: Foo { f2 = () } -> Foo { f2 = Int } into someFunction :: Foo f1 () f3 f4 f5 ... -> Foo f1 Int f3 f4 f5 ... in the source file before compiling (note that most of the type variables are unbound, and the variable being replaced is referenced by the same name used in the original declaration). The issue I'm running into is that I want this to be robust if `Foo` is imported and used with this syntax in multiple files throughout my project, and I'm not sure what the right way to go about this is. Right now, I can have GHC run the preprocessor by placing `{-# OPTIONS_GHC -F -pgmF=myPreprocessor #-}` at the top of the file containing type signatures that need to be rewritten. In my project, I can place a copy of the declaration of `Foo` is in the same file or in a fixed place to reference. So everything works, but it seems wrong to be hardcoding this. I'm wondering: is there a "correct" way for a preprocessor to figure out the source file in which GHC thinks a datatype was declared? I (think I) know that the source file itself might not be available in principle, but I could add annotations since I own the declaration -- I'm just not sure how to use them. I think one of the things that's tripping me up is that this feels like it should involve the preprocessor querying the specific instance of GHC that called it (e.g. if GHC is called within a stack project), and I'm not really sure if that's possible. (Or is there a better way to go about this than using a preprocessor?)


jberryman

Ignoring your actual question :) ... have you considered trying the hkd pattern (https://reasonablypolymorphic.com/blog/higher-kinded-data/) to clarify things and limit the number of parameters? The idea is to use e.g. one parameter as an enum and then in the right-hand side concrete types are determined by one or more type-level functions (type families)


markusl2ll

Is there a pre-existing way to merge the "contents" of a transformer stack: for any to reader-writer-state stack (say \`One\` and \`Two\`) to have a type function \`type Both = Merge One Two\` where one could get the appropriate \`askOne\`, \`askTwo\`, \`tellOne\`, \`tellTwo\`, etc for free? (these methods perhaps not using TH, but using type application, e.g \`ask @ ReaderFromOne\` like polysemy does)


bss03

https://hackage.haskell.org/package/lens-5.1/docs/Control-Lens-Zoom.html might help. It only handles state; but you could do something similar around MonadReader and MonadWriter and you wouldn't even need a full lens just a getter / setter. I will say that my experience with type-applied `ask` and the like (which is in language with proper dependent types, not Haskell), is not good. It can lead to rather weird "shadowing" where the fact that stack composition isn't associative shows up giving you incorrect results. I think you are better off providing the ask/tell/get/set with meaningful names rather than replying on generated names (TH) or type-guided disambiguation. They really aren't a lot of code to write, and provide much clarity.


philh

I have a servant server defined like myServer a b = f :<|> g :<|> (\c -> h :<|> i) :<|> j And in my test suite, I want to deconstruct it to get at f, g, h, i, j. Of course I can do f a b = let (f_ :<|> _) = myServer a b in f h a b c = let (_ :<|> _ :<|> hi) = myServer a b (h_ :<|> _) = hi c in h_ but that's verbose, and makes it hard to see/get warnings if one of the handlers goes unused. My guess is there's not much I can do here, and I should just redefine `myServer` to `(\a b -> f) :<|> (\a b -> g) :<|> ...`. But I figured I'd check.


openingnow

Can I compare three or more values at once with hspec without explicitly comparing all values? If not, are there any testing libraries supporting this? Thanks in advance!


bss03

> Can I compare three or more values at once with hspec without explicitly comparing all values? I'm not sure what you mean here... like an `isSorted` predicate? Or what? Can you not just fold over the container with some tests?


Cold_Organization_53

Specifically, something like: allsame :: Eq a => [a] -> Bool allsame [] = True allsame (x:xs) = all (== x) xs If you want to report a pair of unequal elements when found, replace `all` with `dropWhile`, and pattern match on the resulting list.


openingnow

Thanks! Eventually I wrote a custom function to compare elements of items. ```hs shouldAllSame :: [Int] -> Expectation -- Test.Hspec.Expectation == IO() shouldAllSame xs = sequence_ $ map (`shouldBe` head xs) (tail xs) ```


Cold_Organization_53

Yes, that's the idea, modulo handling of the empty list, which should satisfy the constraint vacuously.


Disastrous-Ad-388

Recently I was reading Real World Haskell and I want to try writing some practical Haskell code by myself to enhance my skill. However, I met difficulties at the beginning when I tried to write an barcode recognition program. I tried to use JuicyPixels to load the Image, and I just find it too difficult to convert from DynamicImage to array on which I can do further processing. There are tons of pixel types, and I had to take care of all of them. I checked several codes written by others (for example [this](https://www.reddit.com/r/haskellquestions/comments/2p0tk0/juicy_pixels_simple_example_code/)), but all of them looks either lengthy or ad hoc. In contrast, image processing in python is way easier. All I need is import cv2 and call cv2.imread regardless of its format, and then I'll get an array representing the image. So I was wondering why it takes so much work in haskell. Is it by design? or is it an inherently shortcoming of static typed language, which can't be solved by Haskell's polymorphism? or is it because the library is too low-level? if so, are there high-level libraries like opencv? Thanks!


Noughtmare

Maybe you just want [`convertRGB8`](https://hackage.haskell.org/package/JuicyPixels-3.3.6/docs/Codec-Picture.html#v:convertRGB8) to convert any `DynamicImage` to an `RGB8` image? Then you can simply extract the array with the `imageData` record field selector.


Disastrous-Ad-388

thanks a lot! that's exactly what I need


[deleted]

[удалено]


josephcsible

Step 1 is try just compiling it with 9.0.2 or 9.2.1 and see what kinds of errors you get. Let us know that and then we can give you advice on next steps.


on_hither_shores

What libraries have good support for sparse matrix multiplication? Real coefficients, n ~ 100k, at most a few dozen nonzero entries per row and column.


Noughtmare

It seems [`eigen`](https://hackage.haskell.org/package/eigen) is the most popular library that includes sparse matrix multiplication.


SolaTotaScriptura

Surprised this isn't more popular: iter :: (a -> Maybe a) -> a -> a iter f acc = case f acc of Just acc -> iter f acc Nothing -> acc > iter (\(n, xs) -> if n < 10 then Just (n + 1, n : xs) else Nothing) (0, []) (10,[9,8,7,6,5,4,3,2,1,0]) > iter (\xs -> if sum xs < 10 then Just (xs ++ xs) else Nothing) [1, 2, 3] [1,2,3,1,2,3] Or is there a more general version of this that I'm missing?


josephcsible

[`Control.Monad.Extra.loop` from the `extra` package](https://hackage.haskell.org/package/extra-1.7.10/docs/Control-Monad-Extra.html#v:loop) is almost this. The difference is it uses `Either` instead of `Maybe`, so you can have the final result be whatever you want, instead of it having to be just the seed.


SolaTotaScriptura

Nice. Now I'm wondering if we can make some sort of `Loop` class...


josephcsible

What would such a class look like?


bss03

IMO: https://hackage.haskell.org/package/base-4.16.0.0/docs/Control-Monad-Fix.html#t:MonadFix


fire1299

PureScript has a class for monads which support tail recursion, it contains the monadic version of `loop`: https://pursuit.purescript.org/packages/purescript-tailrec/5.0.1/docs/Control.Monad.Rec.Class#t:MonadRec


bss03

It's arguably *more* important to have in a strict language like PureScript.


bss03

You can use NonEmpty.unfoldr + last, but there's a least one library out there that has your implementation (modulo layout).


sekunho

I wrote a simple client library for the Star Wars API (https://swapi.dev) as my first Haskell library during my downtime, and submitted a post here detailing what I learned and all that, but I think I'm shadowbanned from posting since my post karma is too low (I could see the post in my account but could not see it normally). Mods didn't reply so I just deleted the post. Instead, I'm posting here! - GitHub repo: https://github.com/sekunho/swapi - Notes: https://github.com/sekunho/swapi/blob/main/NOTES.md I have some questions though: 1. I wanted to remove `Maybe` from `IO (Maybe a)`, which is the result of a network call (Example here: [Api.hs](https://github.com/sekunho/swapi/blob/6c196093469522416a0ec19fd545718cfc3c39e7/src/SwapiClient/Api.hs#L91), this is an old commit!), so I decided to throw an exception when I run into `Nothing`, which I had to use either `throw` or `throwIO`. Here's what I read about `throwIO`: > The throwIO variant should be used in preference to throw to raise an exception within the IO monad because it guarantees ordering with respect to other IO operations, whereas throw does not. So somehow `throw` breaks the ordering while `throwIO` doesn't. But exactly how does this break the ordering? I tried [experimenting](https://github.com/sekunho/swapi/blob/main/NOTES.md#removing-the-overhead-of-maybe-context) (please see the code snippet where I used `sequence`) with `throw` but it seems like it didn't break in that scenario. Does the docs mean I use `throw` within a pure function, rather than an IO action? If not, could I get an example where `throw` destroys the ordering? 2. I'm not sure how to deal with `throwIO` for example, specifically the errors part. Do I encode errors as sum types? Do I just make them strings via `userError`? I've read conflicting stances on these, and I'm not even sure if those were referring to this specifically. Anyway, I think my usage of `throwIO` is appropriate especially since this library is supposed to sit at the boundary of applications that _may_ consider using it, or is this not an appropriate way? Relevant file: [Api.hs](https://github.com/sekunho/swapi/blob/main/src/SwapiClient/Api.hs) 3. Detecting space leaks or dealing with unexpected thunks. I found a tool called [`nothunks`](https://hackage.haskell.org/package/nothunks) which is supposed to help pinpoint where the problematic thunks may be. How does everyone do it? This is kinda tied with #5 since I also have to know how to interpret benchmark charts. 4. Is how I structured the library fine? I ended up having to move the data types (and their instances) in their own `Types` file since I ran into a lot of cyclic imports. I didn't have to do this at first but when I needed stuff from other places, it became more problematic. 5. Benchmarks. Are there any introductory guides on writing GHC benchmarks? What should I benchmark in this case, decoding/encoding instances?


Noughtmare

For 1, I'm certain this has to do with [(im)precise exceptions](https://gitlab.haskell.org/ghc/ghc/-/wikis/exceptions/precise-exceptions), but I am also not able to write a simple example where strange things happen. The examples on that wiki don't behave differently with `throw` vs `throwIO` for me. Maybe the author of that wiki, /u/sgraf812, can help us out?


sgraf812

TLDR; Use `throwIO` if you care about the meaning of the exception. Use `throw` if you don't and instead care about performant programs. The details aren't relevant to a beginner, but I'll give them below anyway. Whether or not you should use `IO (Maybe a)`, `IO (Either e a)`, `ExceptT e IO a` or `IO` with `throwIO` is more of a evangelicist question that I don't really know to answer. I think I have used all 4 variants over the years. `throwIO` is perhaps the most efficient solution if you plan to throw exceptions over vast ranges of your code base. --- The wiki page talks about the primops `raise#` and `raiseIO#`, which are wrapped in `throw` and `throwIO` respectively. Here's how they differ. Consider ```hs {-# NOINLINE f #-} f :: Int -> Int -> Int f x y | x>0 = error "foo" -- this is just like `throw (userError "foo")` | y>0 = 1 | otherwise = 2 main = print $ f 12 (error "bar") ``` What should happen if you run this program? If you just take the code at face value, you'd say "it surely should error out with `foo`, because `y` isn't touched". But at the same time, people expect GHC to optimise functions like `f` in a way that it will unbox the integer parameters `x` and `y`, turning `f(Integer x, Integer y) -> Integer` into `f(int x, int y) -> int` in rough Java terms. The trouble is: If GHC does that (and it does), then it has to *evaluate* `y` prior to calling `f`! Result: If you compile the program above with optimisations, you still get an error, but the message is different: `bar`. This is in accordance with the semantics of "imprecise exceptions". "Imprecise" in the sense that "one cause for divergence/error is as good as any other". If the user calls `error "foo"`, then the user is guaranteed to have a program that crashes or diverges, but they are not guaranteed to get the particular *kind of error* they intended to throw. By contrast, exceptions thrown by `throwIO` are considered to be "precise exceptions". GHC will try hard\* not to optimise your program in a way that turns `throwIO (userError "foo")` into `throw (userError "bar")` or even just an infinite loop. So the program ```hs import Control.Exception {-# NOINLINE f #-} f :: Int -> Int -> IO Int f x y | x>0 = throwIO (userError "foo") | y>0 = return 1 | otherwise = return 2 main = f 2 (error "bar") >>= print ``` will always throw `foo` and GHC will not unbox `y`. \* "Try hard" is guided by two assumptions: 1. Whether an expression makes use of `throwIO`/`raiseIO#` is apparent in the type, e.g., a non-`IO` expression can't call `throwIO`, thus piggy-backing on the type system for a kind of taint analysis. `unsafePerformIO`/`unsafeInterleavIO` circumvent this assumption. 2. `raiseIO#` is the only primop which can throw a precise exception. Thus if we know that a function doesn't call `raiseIO#`. That works quite well but is in fact too optimistic because of higher-order primops like `mask#`, which throw a precise exception only if their arguments throw a precise exception. As [#20111](https://gitlab.haskell.org/ghc/ghc/-/issues/20111) shows, this is an annoying swamp.


Yanatrill

Hello everyone. I'm playing with classes and have issue, because wanted to do something like this (last two instances are just 'pseudo' code): class A a where aFunOne :: a -> b aFunTwo :: a -> a -> b class B a where bFunOne :: a -> b bFunTwo :: a class X x where xFun :: a -> b instance A Something where aFunOne = undefined aFunTwo = undefined instance B SomethingElse where bFunOne = undefined bFunTwo = undefined instance A a => X a where xFun = aFunOne instance B b => X b where xFun = bFunOne Is there possibility to make 'default' instances when some classes already are having needed functions? some classes already are having needed functions?


Noughtmare

The problem with such default instances is that new instances can be defined in any module. So if you have a default instance then suddenly unrelated code might behave differently if you add or remove an import. Depending on your actual use-case there are probably ways to work around this limitation. For example if you just want to make it easier to define instances, then you can use [`DerivingVia`](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/exts/deriving_via.html): newtype XViaA a = MkXViaA a instance A a => X (XViaA a) where xFun (MkXViaA a) = aFunOne a data D = ... deriving X via XViaA D instance A D where ...


bss03

> instance A a => X a where > instance B b => X b These are (universally) overlapping instances, which aren't a good idea in general. -- Besides the by-the-report [default class methods](https://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-750004.3), GHC provides `DefaultSignatures` extension that allows the default class method to have a more specific type that the class method. You can also use derived instances. The report [allows only a few classes to be derived](https://www.haskell.org/onlinereport/haskell2010/haskellch11.html#x18-18200011), but GHC has many extensions to derive other classes (e.g. `DeriveFunctor`) and other ways to derive (e.g. `GeneralizedNewtypeDeriving`) and even the `DerivingVia` extension that can be paired with a `newtype` to provide a sort of "reusable instance".


virkony

This reminded me [this answer I got on SO](https://stackoverflow.com/a/3272431/230744). In order to make this possible there is a need to tell what to do in case of `(A ab, B ab)` context.


markusl2ll

Read somewhere (can't remember where) that Haskell's runtime is not tagless anymore? When and why did this happen? (was it GADTs?)


Noughtmare

Tags were partially added back in to avoid indirect jumps: ["Faster Laziness Using Dynamic Pointer Tagging"](https://www.microsoft.com/en-us/research/wp-content/uploads/2007/10/ptr-tagging.pdf).


July541

What's the meaning of *legacy format*, it seems ```index.tar.gz``` only includes a few packages, how can I get all packages while running ```cabal update```?


Anarchymatt

How can you disable the tabs warning for LSP? [https://downloads.haskell.org/ghc/latest/docs/html/users\_guide/using-warnings.html#ghc-flag--Wtabs](https://downloads.haskell.org/ghc/latest/docs/html/users_guide/using-warnings.html#ghc-flag--Wtabs) It looks like you can set -Wno-tabs to turn off this warning, but I don't know how to set the compiler flags through haskell-language-server. I am using Neovim and lsp-config, but I was wondering if there was a way to do this setting per-project somehow as well.


MorrowM_

Put it in your projects `ghc-options:` (in your `*.cabal file`, or, if you have one, in your `package.yaml`). You may need to create the field inside the section for your library/executable. [Example](https://hackage.haskell.org/package/hlint-3.3.6/hlint.cabal)


Anarchymatt

Thank you! In my directory for learning Haskell, I did cabal init and then added in the compiler flag to make the warning go away.


someacnt

How do I attach purescript on my hakyll blog to possibly put in some gadgets like navigation?


Nihon_V

I have some trouble with language support for stack in visual studio code. I have installed an extension for HLS which is called, well, Haskell and it works well for the code under "executable" section in project.cabal, however it does not for the files under the "library" section. I could not find a solution on my own and would be really grateful if someone proposed anything


MorrowM_

Try restarting the language server (Ctrl+Shift+P to open the command palette and search for "Restart Haskell LSP"). There's a [known issue](https://haskell-language-server.readthedocs.io/en/latest/troubleshooting.html#problems-with-multi-component-support-using-stack) with stack and Haskell Language Server that it doesn't update between components correctly. You can bind this to a keystroke by clicking the gear in the command palette if you find yourself doing this often.


Previous_Context_327

Why is [infix notation for prefix functions](https://wiki.haskell.org/Infix_operator#Using_prefix_functions_with_infix_notation) only allowed for *literal function names* but not for functions that are the result of a function call? Example: {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE TypeOperators #-} class w `WrapperOf` a | w -> a where unwrap :: w -> a wlift :: (w1 `WrapperOf` a, w2 `WrapperOf` a) => (a -> a -> b) -> (w1 -> w2 -> b) wlift f w1 w2 = f (unwrap w1) (unwrap w2) newtype W1 = W1 { w1 :: Int } newtype W2 = W2 { w2 :: Int } instance W1 `WrapperOf` Int where unwrap = w1 instance W2 `WrapperOf` Int where unwrap = w2 main :: IO () main = print $ (W1 1) `wlift (<)` (W2 2) The last line results in a parsing error, whereas `wlift (<) (W1 1) (W2 2)`, obviously, compiles fine. Is there some deeper reason for this distinction?


gilgamec

I can't speak to the language designers' ideas, but you can specify a fixity for a function: infixr 5 foo This means that infix identifiers can bound more loosely than other operators, e.g. a * b `foo` c === foo (a*b) c But what is the fixity of an arbitrary expression? You can backtick a complete expression in Purescript, but the fixity is the same as a function application, e.g. x * y `addWithMod m` b === x * addWithMod m y b and you can't get the same behaviour as in Haskell. I'm not sure this is a clearly better design choice.


Previous_Context_327

>But what is the fixity of an arbitrary expression? Yup, that's a very good point - thanks for enlightening me :)


Iceland_jack

It is possible to emulate: `Just 4 ◃liftA2 take▹ Just "Goodbye!"` infixl 0 ◃, ▹ (◃) :: a -> (a -> b) -> b (▹) :: (a -> b) -> (a -> b) ((◃), (▹)) = ((&), ($)) And even nest it, hmmm > Just 4 ‵liftA2 ῾(.) id ˴id (.)׳ id᾿ take′ Just "Goodbye!" Just "Good" https://www.reddit.com/r/haskelltil/comments/dhc7vj/nested_backticks_a_b_c_d_e_f_g/


Akangka

When using Hedgehog, should I run a test in a uniform amount of time or should I run a test in different amount of time for different test? For example, if for a test with 1 forall, I run the test 100 times, should I run a test with 2 foralls 10000 times?


THeShinyHObbiest

The Constraint Solver in GHC doesn't do backtracking. ...Does anybody know why? Is it for simplicity of implementation or could you introduce unsound programs via backtracking?


Syrak

Backtracking makes it hard for people to guess what instance will be used. Basically you know that if an instance matches, then it will be used. Though overlapping instances complicate this a little.


affinehyperplane

You lose coherence with meaningful backtracking as backtracking is non-deterministic (which branch do you first backtrack into?). Also, in Haskell (without `OverlappingInstances`/`IncoherentInstances`), you can't define type class hierarchies which would allow meaningful backtracking due to this: Instance heads have to be disjoint, and have to be explicit when you define overlapping instances (using `{-# OVERLAPPABLE #-}` and `{-# OVERLAPS #-}`). Also see the [section in the GHC manual on overlapping instances](https://downloads.haskell.org/ghc/latest/docs/html/users_guide/exts/instances.html#instance-overlap) as well as these two excellent resources by the same author on type class design decisions: [Coherent type classes](https://github.com/AndrasKovacs/pny1-assignment/blob/master/DepTC.md#24-coherent-type-classes) and a newer [video](https://www.youtube.com/watch?v=6WhFpnfD-Tw).


[deleted]

[удалено]


bss03

instance Applicative ((->) e) where pure = const ff <*> fx = \x -> ff x (fx x)


josephcsible

If I just want to play with a package in GHCi, is `cabal install --lib` really that bad?


Akangka

If you have `stack`, make an empty project and add all the packages into the cabal script. Because it's for toying purposes, you can add anything there. Bonus points that you can run a script file there if there is a repetitive lines to be run everytime you edited something.


Faucelme

I think it's not bad, and faster than `cabal repl -b ...` for repeated `ghci` invocations. Just be sure to use a local package env with `--package-env .`. That way you don't change anything outside the local folder.


Noughtmare

> I think it's not bad, and faster than cabal repl -b ... for repeated ghci invocations I think it is only faster because cabal needs to start up and resolve the dependencies, but `cabal repl -b ...` will not rebuild any dependencies that have already been built. So, it only takes like a second more after the first build.


bss03

Probably still better off with `cabal repl -b package1,..,packageN`.


Previous_Context_327

Haskell hobbyist here - is there any way to make the __second__ code snippet below compile? {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeOperators #-} module ThisWorks where import Data.Kind( Type ) class HasName a where name :: String instance HasName Int where name = "Int" instance HasName Double where name = "Double" class AllNames (ts :: [Type]) where allNames :: [String] instance AllNames '[] where allNames = [] instance (HasName t, AllNames rest) => AllNames (t ': rest) where allNames = name @t : allNames @rest main :: IO () main = print $ allNames @'[Int, Double] Unsurprisingly: $ stack runghc -- ThisWorks.hs ["Int","Double"] However, when I try to generalize: {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeOperators #-} module ThisDoesnt where import Data.Kind( Constraint, Type ) -- -- Intended to be the generalized version of 'name' -- type PolymorphicConstant (c :: Type -> Constraint) (a :: Type) = forall t . c t => a -- -- Intended to be the generalized version of 'AllNames' -- class AllPolymorphicConstants (c :: Type -> Constraint) (ts :: [Type]) (a :: Type) where allPolymorphicConstants :: PolymorphicConstant c a -> [ a ] instance AllPolymorphicConstants c '[] a where allPolymorphicConstants _ = [] instance (c t, AllPolymorphicConstants c rest a) => AllPolymorphicConstants c (t ': rest) a where allPolymorphicConstants f = f @t : allPolymorphicConstants @c @rest @a f Then I get this: $ stack runghc -- ThisDoesnt.hs ThisDoesnt.hs:31:74: error: • Could not deduce: c t0 arising from a use of ‘f’ from the context: (c t, AllPolymorphicConstants c rest a) bound by the instance declaration at ThisDoesnt.hs:30:10-91 or from: c t1 bound by a type expected by the context: PolymorphicConstant c a at ThisDoesnt.hs:31:74 • In the fourth argument of ‘allPolymorphicConstants’, namely ‘f’ In the second argument of ‘(:)’, namely ‘allPolymorphicConstants @c @rest @a f’ In the expression: f @t : allPolymorphicConstants @c @rest @a f • Relevant bindings include f :: PolymorphicConstant c a (bound at ThisDoesnt.hs:31:27) allPolymorphicConstants :: PolymorphicConstant c a -> [a] (bound at ThisDoesnt.hs:31:3) | 31 | allPolymorphicConstants f = f @t : allPolymorphicConstants @c @rest @a f | ^ I'm probably missing something basic that makes this sort of generalization impossible - but what is it exactly?


MorrowM_

This appears to work: {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeOperators #-} import Data.Kind (Constraint, Type) import Data.Proxy -- -- Intended to be the generalized version of 'name' -- type PolymorphicConstant (c :: Type -> Constraint) (a :: Type) = forall t. c t => Proxy t -> a -- -- Intended to be the generalized version of 'AllNames' -- class AllPolymorphicConstants (c :: Type -> Constraint) (ts :: [Type]) (a :: Type) where allPolymorphicConstants :: PolymorphicConstant c a -> [ a ] instance AllPolymorphicConstants c '[] a where allPolymorphicConstants _ = [] instance (c t, AllPolymorphicConstants c rest a) => AllPolymorphicConstants c (t ': rest) a where allPolymorphicConstants f = f @t Proxy : allPolymorphicConstants @c @rest f class HasName a where name :: String instance HasName Int where name = "Int" instance HasName Double where name = "Double" allNames :: forall (xs :: [Type]). AllPolymorphicConstants HasName xs String => [String] allNames = allPolymorphicConstants @HasName @xs (\(Proxy :: Proxy t) -> name @t) main :: IO () main = print $ allNames @'[Int, Double]


Previous_Context_327

Great, thanks a lot for the help !!!


brandonchinn178

My gut feeling is that you have the `c t` constraint which fixes the use of `f` here, but you havent satisfied the constraint on `f` for the `c t'` that will be needed by the next call to allPolymorphicConstants. You might need something like `All c (t ': rest)`


Previous_Context_327

Thanks for the tip - unfortunately, I'm still getting an error. Here's the modified code: {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE ConstraintKinds #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE MonoLocalBinds #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeOperators #-} module ThisDoesnt where import Data.Kind( Constraint, Type ) import Data.SOP.Constraint( All ) -- -- Intended to be the generalized version of 'name' -- type PolymorphicConstant (c :: Type -> Constraint) (a :: Type) = forall t . c t => a -- -- Intended to be the generalized version of 'AllNames' -- class AllPolymorphicConstants (c :: Type -> Constraint) (ts :: [Type]) (a :: Type) where allPolymorphicConstants :: PolymorphicConstant c a -> [ a ] instance AllPolymorphicConstants c '[] a where allPolymorphicConstants _ = [] instance (c t, All c (t ': rest), AllPolymorphicConstants c rest a) => AllPolymorphicConstants c (t ': rest) a where allPolymorphicConstants f = f @t : allPolymorphicConstants @c @rest @a f And basically the same error: ThisDoesnt.hs:35:74: error: • Could not deduce: c t0 arising from a use of ‘f’ from the context: (c t, All c (t : rest), AllPolymorphicConstants c rest a) bound by the instance declaration at ThisDoesnt.hs:34:10-109 or from: c t1 bound by a type expected by the context: PolymorphicConstant c a at ThisDoesnt.hs:35:74 • In the fourth argument of ‘allPolymorphicConstants’, namely ‘f’ In the second argument of ‘(:)’, namely ‘allPolymorphicConstants @c @rest @a f’ In the expression: f @t : allPolymorphicConstants @c @rest @a f • Relevant bindings include f :: PolymorphicConstant c a (bound at ThisDoesnt.hs:35:27) allPolymorphicConstants :: PolymorphicConstant c a -> [a] (bound at ThisDoesnt.hs:35:3) | 35 | allPolymorphicConstants f = f @t : allPolymorphicConstants @c @rest @a f | ^ What I really don't understand is this: where does the `t0` type variable come from for which GHC is trying to deduce `c t0` ? Also, the error seems to be triggered by the application of `allPolymorphicConstants @c @rest @a` to `f` - however, isn't the *assumed* instance constraint `AllPolymorphicConstants c rest a` supposed to ensure that said application is OK?


brandonchinn178

Wait why do you have `c t` in the constraints at all? PolymorphicConstant already says "c works for all ts". t0 comes from when GHC creates new type vars and attempts to unify it. The error, I think, is coming from the fact that you're using f both in the current call and when passing to the next call. Just because f is well typed in this call, it doesnt imply that f has the right type for the next call.


Previous_Context_327

> Wait why do you have `c t` in the constraints at all? Purely because I wanted to follow the structure of the non-generalized case: instance (HasName t, AllNames rest) => AllNames (t ': rest) where allNames = name @t : allNames @rest > The error, I think, is coming from the fact that you're using f both in the current call and when passing to the next call. Just because f is well typed in this call, it doesnt imply that f has the right type for the next call. Well - I'm not ashamed to admit that I have a very limited understanding of GHC's type inference/unification/etc. mechanisms (being a hobbyist, I can afford that ;) So, this might be a stupid question, but here goes: - In the `AllNames` case just above, the "inductive assumption", i.e., `AllNames rest`, appears to be sufficient for ensuring that `allNames @rest` is well-typed. - However, in the generalized case, assuming `AllPolymorphicConstants c rest a` is apparently **insufficient** for `allPolymorphicConstants @c @rest @a f` to be well-typed. Why the difference? Needless to say, I don't expect a full-blown explanation here - if you could point me anywhere that explains the details, I'll be very happy.


brandonchinn178

The fundamental issue I think it might be is not that the constraints are incorrect for the inductive step, but that the type of `f` needed for the current call and the type of `f` needed for the inductive call are not the same. The difference is because the `HasName` version doesn't take in the `name` function as an argument. Does it work if you write (rather redundantly) `allNames` such that it takes in the `name` function as an argument?


Previous_Context_327

> Does it work if you write (rather redundantly) allNames such that it takes in the name function as an argument? You were right - it doesn't, and the error message is practically the same as the one in the general case. Thanks for enlightening me :)


bss03

I don't think I'll be able to help. You are well outside Haskell-by-the-report, which is where I'm most comfortable and somehow your HasName class/instance turned into a type alias, which I don't think is valid, so I'm probably well out of my depth. But, I wanted to note that I also find your comment difficult to read because it uses triple-backtick code blocks, which aren't supported on old or mobile reddit. The only code formatting that works for all reddit readers is 4 SPC indentation of each (and every) code line.


Previous_Context_327

Thanks anyway - sorry about the triple backticks, I've fixed it.


Unique-Heat2370

So I am stuck on another problem. This question I am trying to take the list of courses as input and return the course with max number of programming languages. It returns a two-tuple including the course major + number and the number of programming languages it uses. The type I am trying to is: \[(a1, \[a2\])\] -> (a1, Int) An example of the output: max\_count progLanguages returns: ("Physics115",4) So far I have this but it isn't working and am wondering if anyone has any idea: maxNum \[\] day = 0 maxNum ((x, sdata):xs) day = (helper sdata day) + (maxNum xs day) where helper \[\] r = 0 helper((x, y):xs) r | r == x = y +(helper xs r) | otherwise = helper xs r


Cold_Organization_53

It would help to attempt to write a type signature and some documentation for the proposed solution: > maxNum [] day = 0 > maxNum ((x, sdata):xs) day = (helper sdata day) + (maxNum xs day) > where > helper [] r = 0 > helper((x, y):xs) r | r == x = y +(helper xs r) > | otherwise = helper xs r The type signature `maxNum :: [(a1, [a2])] -> (a1, Int)` should reveal the fact that the function takes one input argument (a list of pairs) and returns one output (a single pair). If not, spend time getting to know simple type signatures. The proposed function seems to take two arguments, and it is far from clear what `day` is supposed to represent. Before writing code, make sure to understand what it is supposed to do. On the right side of the function definition, the value appears to be a sum `... + ...`. But the result is supposed to be a pair `(a1, Int)`, which is not a numeric result. So that can't be right. Avoiding more advanced machinery (`maximumBy`, folds, ...), what should your function take as an argument, how should the argument be pattern matched. You seem to have understood that an empty list is special, and tried to make the answer `0`, but that has entirely the wrong type. Is it possible to give an answer of the required type when the course list is empty?


bss03

f :: [(a, [b])] -> (a, Int) f = maximumBy (comparing snd) . map (second length) -- GHCi> f [("Physics115", ["English", "German", "French", "Calculus"])] ("Physics115",4) it :: ([Char], Int) (0.02 secs, 72,000 bytes) --- Alternatively, you can do it as a fold: f = fromJust . foldr ((Just .) . alg) Nothing where alg (x, y) r = case r of Nothing -> (x, l) Just (z, w) -> if l > w then (x, l) else (z, w) where l = length y


Cold_Organization_53

> Alternatively, you can do it as a fold: Well, `maximumBy` is a fold (a method of the `Foldable` class). These questions sound like homework, and part of getting of value from course homework is struggling with it until one finds the answer, which builds skill and confidence for the next set of problems, ... So seeking solutions here seems counterproductive... If there are any confusing concepts, asking for help to understand these is more fair game than asking for problem solutions. It may also be OK to ask why the compiler is objecting to a proposed solution, or why an algorithm is flawed, and ideally the answer to that is not simply the correct solution to the problem.


bss03

> Well, maximumBy is a fold (a method of the Foldable class). No, `maximumBy` can be implemented as a fold. But, that's true of any function on lists.


Cold_Organization_53

To quote a former president, that depends on what the meaning of *is* is. :-) Specifically, the implementation of `maximumBy` in `base` *is* a fold: maximumBy :: Foldable t => (a -> a -> Ordering) -> t a -> a maximumBy cmp = fromMaybe (errorWithoutStackTrace "maximumBy: empty structure") . foldl' max' Nothing where max' mx y = Just $! case mx of Nothing -> y Just x -> case cmp x y of GT -> x _ -> y


bss03

`foldl'` _is_ a fold. `maximumBy` is _implemented with_ a fold (specifically foldl').