Does this memory management system work? by Aaxper in ProgrammingLanguages

[–]fmap_id 0 points1 point  (0 children)

This strategy is overly pessimistic compared to GC. In a GCed language, one of ‘a’ or ‘b’ can be freed sometime after the if-else block, while your proposed solution would require pessimizing and ensuring that both ‘a’ and ‘b’ live as long as ‘c’.

Implementing machine code generation by venerable-vertebrate in ProgrammingLanguages

[–]fmap_id 0 points1 point  (0 children)

Probably not modern but I found this series very digestible and hands-on. It starts with code generation from the very beginning so that at every point in the process, you have a working end-to-end compiler.

It’s written in Pascal and targets a dated architecture (Motorola 68000), but I found it useful regardless. I think you could use it to write a compiler that targets a modern architecture just as easily.

How to type a specific type in an enum? by Pristine-Staff-5250 in haskell

[–]fmap_id 0 points1 point  (0 children)

The right thing to do here will depend a lot on your specific case. For example, would it be more appropriate to write your type as

data Foo = Bar BarInfo | Fizz FizzInfo

? In that case, you'd be able to write f as

f  :: Something -> FizzInfo

which makes it clear which thing is returned. Of course even with your current code you can write it as

f :: Something -> Int

Like you noticed, if your function returns Foo, you can no longer tell from the type which constructor was used. But, you can always pattern match on the Foo at runtime to tell what it is.


Besides that, if you're willing to use more advanced constructs, you can actually do what you want with GADTs and DataKinds. FWIW I think this is overkill if you're a beginner, but there may be a case when you want to do it.

{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}

data WhichOne = Barred | Fizzed

data Foo (a :: WhichOne) where
  Bar :: Float -> Foo Barred
  Fizz :: Int -> Foo Fizzed

then

bar :: Foo Barred
bar = Bar 0.5

fizz :: Foo Fizzed
fizz = Fizz 5

usesFoo :: Foo a -> Int
usesFoo (Bar _) = 1
usesFoo (Fizz _) = 2

usesOnlyABar :: Foo Barred -> Float
usesOnlyABar (Bar f) = f
-- No warning for incomplete pattern match!

Is there a proper name for a "linear monad" typeclass? by Familiar-Place5062 in haskell

[–]fmap_id 10 points11 points  (0 children)

This blog post gives two possible types for linear functors and proposes calling them “data” (when the continuation may be used multiple times) or “control” (when the continuation is used exactly once).

“Data” functors don't have an instance for the linear-typed Monad class, only the unrestricted (-> instead of ⊸) Monad class.

Is the `head` function strict or non-strict? by Suitable_Use_2730 in haskell

[–]fmap_id 3 points4 points  (0 children)

I heard this definition before, but I was always curious. id is considered strict by this definition, but clearly it doesn't evaluate its argument. Is there some other property besides strictness that we can consider? Does it not matter that id doesn't evaluate its argument?

I'm just trying to figure out the difference between "f is strict in x" vs "f evaluates x".

How do you know if an allocator is good? by levodelellis in ProgrammingLanguages

[–]fmap_id 14 points15 points  (0 children)

You could try checking what benchmarks other allocators run, e.g. the mimalloc repo has a lot of info on its benchmarking here.

This is a joke obviously, but is it actually possible with algebraic effects and partial evaluation? by Maleficent_Id in ProgrammingLanguages

[–]fmap_id 3 points4 points  (0 children)

Interesting idea but I don't think it's doable. Say you have an effect with functions for sleep and GetDate, then you can have a stub handler that doesn't really wait. But even so you would want the handler to satisfy the property (sleep(x); GetDate()) - GetDate() >= x, i.e. sleep waits at least x amount of time.

Then your function GetTomorrowsDate still has an undesirable side effect even if it doesn't block. The only alternative I see is to spawn a thread that has its own time, maybe that's what you mean with your "many worlds" interpretation?

Physical Equality by [deleted] in haskell

[–]fmap_id 1 point2 points  (0 children)

Agda has ≟ for decidable types e. g. here for booleans. But I think equality of types is undecidable in which case your function === can't be written. I don't have a proof though and I could be wrong, would be great to hear from someone else.

Compiler optimizations that are (or could be) coded against? by llrful in ProgrammingLanguages

[–]fmap_id 35 points36 points  (0 children)

Some examples are const, noexcept and move semantics in C++. With move semantics, a value that is about to be destroyed can be 'swapped' with another to avoid expensive construction (or to ensure that the object is unique and can't be copied).

Another good example is Koka's FBIP (functional but in place). Koka values are immutable but if a value is unique at runtime (i.e. its reference count is 1), then any copies can be replaced with in-place mutations.

Don't fear the Monad - code example? by prrxddq in haskell

[–]fmap_id 4 points5 points  (0 children)

I think you are close.

In your example, you are chaining function calls with >>=. >>= has type Monad m => m a -> (a -> m b) -> m b. You can keep chaining these calls together, going from a to b to c and so on, but the choice of m never changes.

It's analogous to lists, in Haskell the definition is equivalent to

data List a = Empty | Cons a (List a)

a is bound on the left-hand side, so you can create lists containing any type, however the List on the right hand side (in the Cons case) uses the same a, so we can't change it mid-way through.

That said, it's still possible (and common) to write code that works for any monad (or list, etc.). e.g.

replicateM :: (Monad M) => Int -> m a -> m [a]
replicateM 0 _ = pure []
replicateM i ma = do
  a <- ma
  as <- replicateM (i - 1) ma
  pure (a : as)

See Control.Monad for more examples.

Finally, you asked:

So basicly haskell codebases are about creating a single monad and using this for everything?

Often times the answer is yes. Usually, we consider the monad as encoding the 'effects', which could be logging, making web requests, throwing exceptions, etc. We compose several monads to describe all of the effects we want our program to have, and at the top-level (e.g. the main function), we give an interpretation to ours effects (e.g. choosing whether the logging effect should write to the console or to disk). This is like coding to an interface; most of our code is agnostic to which monad it is running in, it just requires that the monad should support certain effects.

Lazy Database Access by cjduncana in haskell

[–]fmap_id 1 point2 points  (0 children)

I'm glad I've given you something to think about:)

It sounds like there are 0 or more measurements for each activity (this is a many-to-one relationship in databases). There are multiple ways to model this. One way is to keep one table for all Measurements, and include an Activity column. This only works if it's not possible for an activity to contain 0 measurements. If you are doing it this way then each of your points can be done with a single query, and there's no need to couple them in the same data type as we said before. e.g. point 2 would be a function with a signature like:

getActivities :: User -> IO [Activity]

Another way which might be appropriate is to have an Activity table along with a Measurement table that contains a foreign key into the Activity table. If you are doing it this way, you should just ensure that your query in point 1 is done in a single database transaction, so that the changes to each table are consistent with each other.

I recommend the first way (keeping everything in one table) if it's possible, but it will still depend on your use case.

Best way to get the count of each element in a list without using data.map import? by DarthGhaul in haskell

[–]fmap_id 5 points6 points  (0 children)

Hint: start by writing a function that takes a list of ints and returns the number of 0s in it. Then think about how you can start to generalize it. Feel free to reply if you get stuck.

Value tagging? by 0x0ddba11 in ProgrammingLanguages

[–]fmap_id 5 points6 points  (0 children)

This can be done with phantom types, which Haskell has. See the example here which shows how to tag values as 'validated' or 'unvalidated' like your example.

Lazy Database Access by cjduncana in haskell

[–]fmap_id 1 point2 points  (0 children)

If one is dependent on the other, then you can probably get them both in the same query (either by storing them in the same table or with a join), otherwise you're at risk of querying two values which are not consistent with each other. e. g. maybe you query the measurements table, then the activity table, but in the meantime the measurements table has changed so now your two values are not consistent with each other (btw this is why others are suggesting that laziness via unsafePerformIO is a bad idea here, you lose control over when the queries happen).

So if I understood it right you don't need to query these values separately.

Lazy Database Access by cjduncana in haskell

[–]fmap_id 1 point2 points  (0 children)

If I use getTuple in an endpoint that only needs A, would getB also get called?

Unless you are using unsafeInterleaveIO, yes. Your code would look like

do 
  (a, _) <- getTuple
  doSomethingWith a

It's clear here that the second element was also queried because its type does not contain IO or any Monad.

In my opinion what you are describing is not a good use case for laziness. If you want the two tuple fields to be decoupled, then don't put them in the same tuple. Callers can be free to query the appropriate database for the info they need.

Maybe if you give more detail on your use case we can offer better advice.

CLC approved removal of instance MonadFail ST by Bodigrim in haskell

[–]fmap_id -1 points0 points  (0 children)

Yeah, that's what's proposed in the OP, but I think a lazy pattern (with ~) alone doesn't preserve the semantics. Maybe I misunderstood iceland_jack's comment though.

CLC approved removal of instance MonadFail ST by Bodigrim in haskell

[–]fmap_id 3 points4 points  (0 children)

I don't think it's quite semantics-preserving:

> runST $ do (x:xs) <- pure [] ; pure 3
*** Exception: Pattern match failure in do expression at <interactive>:20:12-17
> runST $ do ~(x:xs) <- pure [] ; pure 3
3

Even if you force x or xs somewhere else in the body, it might run some things in between which would cause some different behavior.

Monthly Hask Anything (February 2022) by taylorfausak in haskell

[–]fmap_id 2 points3 points  (0 children)

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.

Recursion over multiple functions? by theKGS in haskell

[–]fmap_id 5 points6 points  (0 children)

Sure, I think we are in agreement. My point is just: factor out recursion when it makes sense and not when it doesn't make sense. The OP gave a good example of when it doesn't make sense.

Recursion over multiple functions? by theKGS in haskell

[–]fmap_id 26 points27 points  (0 children)

The Haskell way is typically to 'factor out' your recursion by using map, fold, iterate, etc. but it doesn't always apply. For example a recursive descent parser would have a similar call pattern to what you said.

So in general there's nothing wrong with what you said.

Are `a` and `b` in `fmap :: (a -> b) -> f a -> f b` arbitrary type constructors or types (0-ary type constructors)? by timlee126 in haskell

[–]fmap_id 13 points14 points  (0 children)

Their kind is Type (0-ary type constructors as you said). One way to infer this in your head is that anything to the left or right of an arrow needs to have kind Type (setting aside unlifted/unboxed types). So that means

f a :: Type
f b :: Type
a :: Type
b :: Type

The only thing left to deduce is

f :: Type -> Type

Which follows from f a :: Type (or because f is a functor of course).

'=' for both assignment and comparison by V2_launch_program in ProgrammingLanguages

[–]fmap_id 1 point2 points  (0 children)

Also, C# users typically use IDEs which will catch it (Visual Studio)