Article didn’t explain the desire to change some common operators, tho it implied it would.
I’m uninterested in trying to graft an alternative front end on to GHC and I don’t think it would actually help the ecosystem much.
If we still had a language standard, I think a transpiler from a new front end to standard Haskell might be interesting. I don’t think the front end is that bad tho. Yes, records are troublesome and several languages have improved on them, but they aren’t often a real pain point for me until they interact with the type system, and a new front end is unlikely to fix that. (Extensible record types ala Purescript might?)
I think it is generally a good idea for an (infix) operator to have a equivalent (prefix) function, but I don’t think requiring at the language level buys you much. Good names is a cultural issue and doesn’t have a technological solution (as much as I want one). People that want to strongly encourage use of an operator will just pick a name that’s hard to type and pronounce and easynto confuse with other names.
I do wish we had mixfix operators ala Agda. I also think more precedence levels might help, tho I’ve always thought having the computer build/verify a transitive closure from pairwise ordering statements would be more flexible.
Anyway, I don’t think this is thought through enough, and I don’t think my thoughts here are complete enough either.
Hello, it seems like September one isn’t up here. Even though this community is quite inactive, wouldn’t it be better to maintain this place? The app ecosystem is shaping up gradually, so one might expect more influx of users.
I've been contemplating the monthly questions threads. At this point I'd be totally fine with small questions being posted in separate threads, that will also make them more noticeable. In fact, you could have made this question/request a new thread.
I'm now considering adding a pinned thread with a longer welcome message and some useful information about this kbin and this magazine. Then I can also suggest sorting by new or active. That can be a place for small remarks but I'll probably not replace it every month. I'd get a bit sad if I had to unpin an empty thread each month.
I am still hopeful for the future. Indeed, mobile applications will probably increase the user counts.
I consider Reflex to be by far the most mature implementation of FRP. Now only if there was a wrapper around a native GUI library like GTK or WxWidgets.
I've spent this evening trying to get conclusive benchmark results, but I have not succeeded with that yet. It seems like this is pretty difficult to benchmark. So I'd like to hear it if someone else is able to get good benchmark results.
createArray :: Int -> a -> (forall s. MutableArray s a -> ST s ()) -> Array a
Create an array of the given size with a default value, apply the monadic function and freeze the result. If the size is 0, return emptyArray (rather than a new copy thereof).
createArray 0 _ _ = emptyArray
createArray n x f = runArray $ do
mary <- newArray n x
f mary
pure mary
thawArray
:: PrimMonad m
=> Array a -- ^ source
-> Int -- ^ offset
-> Int -- ^ length
-> m (MutableArray (PrimState m) a)
Create a mutable array from a slice of an immutable array.
This operation makes a copy of the specified slice, so it is safe to use the immutable array afterward.
Note: The provided array should contain the full subrange specified by the two Ints, but this is not checked.
contents <- C8.readFile filepath
let (encSalt:_:encRest) = C8.lines contents
rest = decodeSecrets encRest
case decodeBase64 encSalt of
Left _ -> error "Decoding error"
Right salt -> pure $ Vault salt rest
Which I would rewrite for a bit more safety
contents <- C8.readFile filepath
case C8.lines contents of
encSalt:_:encRest ->
case decodeBase64 encSalt of
Left _ -> error "Decoding error"
Right salt -> pure $ Vault salt $ decodeSecrets encRest
_ -> error "Decoding error"
Also, note that in this case laziness might do unexpected things. The contents of the vault will only be evaluated once you actually ask for the values. You might want to use strict fields for it like so:
data Vault =
Vault
{ salt :: !ByteString
, secrets :: ![ByteString]
}
But that's not enough, because this will only force the first element (more precisely the first cons-cell). To truly force all values in the list of secrets you'd have to chose another data type. Unfortunately, there's not really any really popular strict vector type. The simplest fix is probably just to do the forcing of evaluation yourself like so:
Right salt -> pure $! Vault salt $!! decodeSecrets encRest
Where $!! is from Control.DeepSeq from the deepseq package.
Thx a lot for your detailed feedback. I already heard about bang notation once, but forgot about it. I think I do understand how laziness works, but I can't understand why it'd be bad if Vault gets loaded into memory the 1st time it's needed. Does GHC split the parsing into multiple operations because salt is used a little earlier than secrets?
It's not that the vault only gets loaded into memory the 1st time it is needed, what will happen is that the secrets will be read into memory in their raw form and only decoded on-demand. So if you only access the first secret, then it will only decode the first secret and not the rest. Haskell's laziness is very granular like that. In this case it indeed is not that big of a deal, because it probably won't use a lot more memory, but I'd still consider it a code smell.
Haskell
Hot