infinisil changed the topic of #nix-lang to: Channel for discussing Nix as a language - https://nixos.org/nix/manual/#chap-writing-nix-expressions - Logs: https://logs.nix.samueldr.com/nix-lang/
ris has quit [Ping timeout: 260 seconds]
ris has joined #nix-lang
Dotz0cat has quit [Ping timeout: 256 seconds]
Dotz0cat has joined #nix-lang
infinisil has quit [Quit: Configuring ZNC, sorry for the joins/quits!]
andremedeiros has quit [Ping timeout: 240 seconds]
andremedeiros has joined #nix-lang
infinisil has joined #nix-lang
rajivr has joined #nix-lang
ris has quit [Read error: Connection reset by peer]
ris has joined #nix-lang
Dotz0cat has quit [Ping timeout: 246 seconds]
blueberrypie has quit [Quit: leaving]
blueberrypie has joined #nix-lang
Dotz0cat has joined #nix-lang
Dotz0cat has quit [Ping timeout: 246 seconds]
Dotz0cat has joined #nix-lang
__monty__ has joined #nix-lang
Dotz0cat has quit [Ping timeout: 260 seconds]
<sterni> nix lang oddity of the day:
<sterni> > -9223372036854775808
<{^_^}> error: invalid integer '9223372036854775808'
<sterni> > --9223372036854775807 - 1
<{^_^}> 9223372036854775806
<sterni> err
<sterni> > -9223372036854775808 - 1
<{^_^}> error: invalid integer '9223372036854775808'
<sterni> > -9223372036854775807 - 1
<{^_^}> -9223372036854775808
<sterni> err
<sterni> now
<sterni> I think this is an off by one somewhere in libexpr
<sterni> ahh this is a parser bug, because negative numbers are parsed as positive numbers
<sterni> which doesn't work out with bounds
evanjs has quit [Read error: Connection reset by peer]
<sterni> because abs(min_int) > max_int
evanjs has joined #nix-lang
<sterni> oh noooooooooo
<sterni> there are no gegative int literals
<sterni> - is an operator
<V> so... -9223372036854775808 is possible to represent (and obtain by addition/subtraction), but not as a literal? cursed
<sterni> exactly
<sterni> ints are always parsed as positive integers
<Profpatsch> why are ints not bigints in the first place
<Profpatsch> I mean we don’t have that many
<Profpatsch> So why arbitrary restrictions, apart from “it was easier to implement at the time”
<ekleog> “doing otherwise would break backwards-compatibility”?
<ekleog> (though interestingly enough… I'd bet any breakage that would happen would only currently be relying on nix code being UB because signed int addition is UB in c++?)
<ekleog> (haven't checked the code that said)
<niksnut> Profpatsch: is there a better reason than "it was easier to implement that way"?
<niksnut> bigint support would require pulling in another library
<V> I mean, if it is indeed implemented directly using C++ primitives, Nix-lang can now directly invoke UB
<V> who knows which optimisations the GCC maintainers are going to implement in the future
<ekleog> TBF signed int overflow being UB is probably actually ID by GCC to mean wrapping on amd64; anything else would most likely break so much real-world software
<V> indeed. if you actually took advantage of that, increment w/out bounds check could cause portions of code to be completely eliminated
<niksnut> well, there have been some security bugs because the compiler removed code under the assumption that integers don't wrap around
<V> but I'm also not relying on them deciding to enable this for -std=c++<future year>, with the argument that this wouldn't apply to "existing software", etc
<niksnut> but I don't think it's an issue, we just inherit the int64_t behaviour
<siraben> how do you exponentiate a number in nix?
<niksnut> you don't :-)
<niksnut> nix arithmetic is really only good for enumerating/counting (e.g. lib.range)
<siraben> aw
<niksnut> nickel only has 64-bit floating-point numbers, which is probably a good idea since they're more standard
<niksnut> and it matches json
<V> siraben: pow = x: y: builtins.fromJSON (builtins.readFile (runCommand "" {} "echo $((${builtins.toString x} ** ${builtins.toString y})) >$out"))
<siraben> what's the status of the nickel language?
<siraben> V: you are crazy!
<siraben> nix-repl> pow 2 3
<siraben> [1 built, 0.0 MiB DL] 8
<V> siraben: I don't deny that
<edef> wait, why involve readFile?
<V> wait, does fromJSON work on files directly?
<edef> `pow = x: y: builtins.fromJSON "${builtins.toString x} ** ${builtins.toString y}"` should do
evanjs has quit [Ping timeout: 240 seconds]
<V> ooooh
<edef> fromJSON just takes a string
<V> no, this is using bash?
<edef> oh
<edef> i see
<edef> ah, i missed the $(( among all the token soup
<V> easy mistake
<edef> i was already fairly confused about how this parsed as valid JSON tbf :p
evanjs has joined #nix-lang
<sterni> > exp = base: pow: if pow > 0 then base * (exp base (pow - 1)) else if pow < 0 then 1.0 / exp base (abs pow) else 1;
<{^_^}> error: syntax error, unexpected ';', at (string):154:116
<sterni> > exp = base: pow: if pow > 0 then base * (exp base (pow - 1)) else if pow < 0 then 1.0 / exp base (abs pow) else 1
<{^_^}> error: undefined variable 'abs' at (string):154:100
<edef> damnit, you're beating me to it
<sterni> > abs = i: if i < 0 then -i else i
<{^_^}> abs defined
<sterni> > exp = base: pow: if pow > 0 then base * (exp base (pow - 1)) else if pow < 0 then 1.0 / exp base (abs pow) else 1;
<{^_^}> error: syntax error, unexpected ';', at (string):155:116
<sterni> > exp = base: pow: if pow > 0 then base * (exp base (pow - 1)) else if pow < 0 then 1.0 / exp base (abs pow) else 1
<{^_^}> exp defined
<sterni> > exp 2 16
<{^_^}> 65536
<V> I love it
<sterni> siraben: ^
<edef> i was going to do full exponentiation-by-squaring
<edef> but this is clever, i like it
<sterni> well it's extremely slow probably
<sterni> because function calls are really expensive
<sterni> I wonder if genList and foldl' are faster in such cases because primops
<sterni> but you still have to evaluate the lambda every time
<siraben> sterni: nice
<edef> clearly we need to have {^_^} report runtime in ms
<edef> and/or have a benchmark mode
<sterni> the worst thing I had so far was my naive ord implementation
<sterni> it took like 3s to convert a list of 255 characters into a byte each
<sterni> because a lot of recursive function calls and string/list indexing originally
<edef> > isOdd = x: (builtins.bitAnd x 1) == 1
<edef> > fastExp = base: exp: if exp < 0 then fastExp (1 / x) -exp else if exp == 1 then 1 else if isOdd exp then base * fastExp (exp - 1) else fastExp (x * x) (x / 2)
<{^_^}> isOdd defined
<{^_^}> fastExp defined
<edef> > fastExp 2 16
<{^_^}> value is a string while an integer was expected, at (string):55:100
<edef> wait, what the hell
<edef> i had a variety of expectations but this was definitely not among them
<edef> oh, i somehow used `x` in half the places for base >_<
<edef> > fastExp = x: exp: if exp < 0 then fastExp (1 / x) -exp else if exp == 1 then 1 else if isOdd exp then x * (fastExp x (exp - 1)) else fastExp (x * x) (x / 2)
<{^_^}> fastExp defined
<edef> > fastExp 2 16
<{^_^}> 1
* V tilts head
<edef> i'm definitely somewhat out of it, but also, i just realised everyone's impl for negative exponents is wrong
<edef> since / does integer division
<__monty__> > fastExp 15 1
<{^_^}> 1
<edef> > fastExp = x: exp: if exp < 0 then fastExp (1 / x) -exp else if exp == 1 then x else if isOdd exp then x * (fastExp x (exp - 1)) else fastExp (x * x) (x / 2)
<{^_^}> fastExp defined
<V> mine just flat out breaks b/c bash doesn't allow for negative exponents. would be trivial to fix though
<edef> > fastExp 2 16
<{^_^}> 4
<V> hey, it's closer to the correct answer
<edef> okay, wow, i really messed up but i'm not actually spotting the mistake yet
<V> well done
<sterni> edef: nope 1.0 / int is okay
<sterni> > 1.0 / 5
<{^_^}> 0.2
<edef> ah
<sterni> you need to make sure you have a float somewhere though
<sterni> nix floats are really bad btw
<edef> > fastExp = x: exp: if exp < 0 then fastExp (1.0 / x) -exp else if exp == 1 then x else if isOdd exp then x * (fastExp x (exp - 1)) else fastExp (x * x) (x / 2)
<{^_^}> fastExp defined
<sterni> > lol = 0.00000000000001
<{^_^}> lol defined
<edef> ah, hold on. i don't have a 0 case
<sterni> lol
<sterni> > lol
<{^_^}> 1e-14
<edef> > fastExp = x: exp: if exp < 0 then fastExp (1.0 / x) -exp else if exp == 0 then 1 else if isOdd exp then x * (fastExp x (exp - 1)) else fastExp (x * x) (x / 2)
<{^_^}> fastExp defined
<edef> > fastExp 2 16
<{^_^}> 4
<edef> >_<
<sterni> > builtins.toString lol
<{^_^}> "0.000000"
<V> I hate it
<sterni> > builtins.toJson lol
<edef> oh
<{^_^}> attribute 'toJson' missing, at (string):484:1
<edef> > fastExp = x: exp: if exp < 0 then fastExp (1.0 / x) -exp else if exp == 0 then 1 else if isOdd exp then x * (fastExp x (exp - 1)) else fastExp (x * x) (exp / 2)
<{^_^}> fastExp defined
<sterni> > builtins.toJSON lol
<edef> > fastExp 2 16
<{^_^}> "1e-14"
<{^_^}> 65536
<edef> there we go
<V> \o/
<edef> didn't spot x/2 vs exp/2 at the tail
<sterni> > builtins.toString 0.000000001 == builtins.toString 0.00000001
<{^_^}> true
<sterni> next competion: implementing sqrt
<edef> oof
<V> are we talking optimised sqrt, or `sqrt = flip exp 0.5`
<edef> i think we might want bit shifts for that? i forget what the implementation techniques are exactly
<edef> i don't think any of the exps here handle noninteger exponents
<V> bash certainly doesn't
<edef> and i think that's ~equivalent to implementing sqrt anyhow
<sterni> V: yeah I guess that is what you want to use at the end of the day
<edef> looks like all the decent approaches are iterative approximation
<sterni> edef: you mean the quake sqrt function?
<edef> that's actually closed-form i believe
<edef> i *was* pondering how we totally need float type punning in nix
<V> exp = x: y: builtins.fromJSON (builtins.readFile (runCommand "" {} "${ruby}/bin/ruby -e 'print ${builtins.toString x} ** ${builtins.toString y}' >$out"))
<sterni> edef: the problem is bit shifts are actually also just exp in nix in the end
<V> > expRuby = x: y: builtins.fromJSON (builtins.readFile (runCommand "" {} "${ruby}/bin/ruby -e 'print ${builtins.toString x} ** ${builtins.toString y}' >$out
<{^_^}> error: syntax error, unexpected DOLLAR_CURLY, expecting ')', at (string):158:8
<sterni> > bitShiftL = bit: count: if count == 0 then bit else (bitShiftL bit (count - 1)) * 2
<{^_^}> bitShiftL defined
<sterni> > bitShiftL 4 4
<{^_^}> 64
<sterni> > bitShiftL 1 4
<{^_^}> 16
<edef> although i think you'd want to use the fast inverse sqrt algo and follow it with one or two iterations of newton's method
<sterni> > bitShiftL 1 10
<{^_^}> 1024
<sterni> > bitShiftL 1 16
<{^_^}> 65536
<V> > expRuby = x: y: builtins.fromJSON (builtins.readFile (runCommand "" {} "${ruby}/bin/ruby -e 'print ${builtins.toString x} ** ${builtins.toString y}' >$out"))
<{^_^}> error: undefined variable 'runCommand' at (string):157:56
<V> > expRuby = x: y: builtins.fromJSON (builtins.readFile (pkgs.runCommand "" {} "${ruby}/bin/ruby -e 'print ${builtins.toString x} ** ${builtins.toString y}' >$out"))
<{^_^}> error: undefined variable 'ruby' at (string):157:81
<V> > expRuby = x: y: builtins.fromJSON (builtins.readFile (pkgs.runCommand "" {} "${pkgs.ruby}/bin/ruby -e 'print ${builtins.toString x} ** ${builtins.toString y}' >$out"))
<{^_^}> expRuby defined
<edef> shame JSON has a base-10 mantissa
<sterni> > fastExp 12489 0.5
<{^_^}> value is a float while an integer was expected, at (string):222:14
<V> > sqrtRuby = lib.flip expRuby 0.5
<{^_^}> sqrtRuby defined
<V> > sqrtRuby 4
<{^_^}> cannot read '/nix/store/aqsdpp1wqxqjldw2pmdh4x51yph8i1aw-unknown', since path '/nix/store/g4cmabksbbsnzxpv0bk1qq2a9ckwyikv-unknown.drv' is not valid, at (string):157:37
<edef> D:
<V> rude
<V> IFD-protection cramping my style
<sterni> V: it doesn't let you build stuff :(
<V> brb switching to guix
<sterni> if I was using guix I wouldn't have an endless supply of cursed facts about my package manager's expression language
<V> if I was using guix I'd not have a cursed package manager
<siraben> Nix is cursed? :(
<V> I mean
<V> did you not see the conversation about float handling up there
<siraben> (the language obviously cursed)
<sterni> nix the package manager also
<sterni> as in the implementation
<V> aye
<siraben> sterni: ooh tell me more
<siraben> like, the C++ codebase?
<sterni> yeah, I'm not that familiar with it actually
<sterni> but a lot of weird stuff in nix the language is a result of implementation stuff I'd say
<sterni> also evaluation could probably be faster
<sterni> and it being overly strict sometimes
<sterni> > builtins.isString "${builtins.throws "lol"}"
<siraben> i see
<{^_^}> attribute 'throws' missing, at (string):487:22
<sterni> > builtins.isString "${builtins.throw "lol"}"
<{^_^}> lol
<sterni> siraben: I guess the critisicm is listed here?! https://code.tvl.fyi/about/third_party/nix
<siraben> interesting, that doesn't compute in my WHNF mental model
<siraben> should be true
<sterni> siraben: indeed nix is being to strict in that case because the string constructor should come first
<sterni> one thing I found really strange when I last had a look in the code is that in the implementation builtins and functions are different things and behave differently, but they have the same type (lambda) in the language
<sterni> which has the consequence for example that builtins.functionArgs throws an exception on nix stable
<niksnut> there is no "string constructor"
<sterni> because it was forgotten to implement that primop for primpos as well
<niksnut> there are values of type string, but you don't know that the argument to builtins.isString is a string value until you've evaluated it, hence the exception
<sterni> i think nixbot uses nixUnstable
<sterni> > buitlins.functionArgs builtins.isString
<{^_^}> undefined variable 'buitlins' at (string):487:1
<sterni> > builtins.functionArgs builtins.isString
<{^_^}> 'functionArgs' requires a function, at (string):487:1
<sterni> oh it doesn't
<sterni> > builtins.typeOf builtins.isString
<{^_^}> "lambda"
<sterni> > builtins.typeOf (_: 12)
<{^_^}> "lambda"
<sterni> > builtins.functionArgs (_: 12)
<siraben> sterni: interesting readme
<{^_^}> { }
<siraben> does it currently work as a drop-in replacement for Nix?
<sterni> niksnut: well you don't have to evaluate the strings contents to know it's a string; depends on implemantion
<sterni> siraben: yes, I think a few people are using it, you have to swap out nix-daemon as well though
<niksnut> the implementation is the language :p
<sterni> niksnut: unfortunately
<niksnut> in the absence of a static type system, you can't really conclude whether the argument to builtins.isString will be a string without evaluating its argument
<siraben> sterni: nice
<simpson> Nix doesn't evaluate strictly enough for that problem to be fixed by simply putting a static type on every value. Same issue as Haskell, where the computational category isn't the one used for intuitive reasoning: https://wiki.haskell.org/Hask
<__monty__> niksnut: But can anything that parses as a string literal ever turn out not to be a string?
<niksnut> no, but the argument to builtins.isString is not an AST but a value/thunk
<niksnut> so it can't really make any clever optimizations about the expected result type
<niksnut> and if it did, it would lead to really weird semantics
<niksnut> where builtins.isString might *sometimes* avoid an exception
<niksnut> e.g. in builtins.isString (if expr then "foo" else throw "bar")
<niksnut> a sufficiently smart interpreter might conclude that expr is always true
<niksnut> sorry, better example: builtins.isString (if expr then "${throw ..}" else 123)
<sterni> I think that could be fine
<sterni> you just can't decide builtins.isString if it is something like "foo" + builtins.throw "lol"
<sterni> but as long as the string is constructed from a literal it should be clear
<sterni> you could also keep this around at eval time just like you would dependent expressions
<sterni> I'd think at least
<infinisil> > :v sqrt
<{^_^}> sqrt = a: let iter = x: let x' = (x + a / x) / 2; d = x' - x; in if d < 0.00001 && d > -0.00001 then x' else iter x'; in iter (a / 2.0 + 0.5)
<infinisil> > sqrt 10
<{^_^}> 3.16228
<infinisil> edef: sterni: ^
<infinisil> > 3.16228 * 3.16228
<{^_^}> 10
<infinisil> > sqrt 0.1
<{^_^}> 0.316228
<infinisil> > sqrt 1.1
<{^_^}> 1.04881
<infinisil> Nice
<siraben> nix already had sqrt? huh
<infinisil> It's just a function defined in the bot here
rajivr has quit [Quit: Connection closed for inactivity]
<sterni> infinisil: nice
<sterni> niksnut: if we didn't have typeOf we could just avoid all exceptions and return true if anything throws
<sterni> like undefined compiles as any type in haskell
<sterni> but alas that doesn't work as we need to decide on a type
<edef> infinisil: nice
infinisil has quit [Quit: Configuring ZNC, sorry for the joins/quits!]
infinisil has joined #nix-lang
__monty__ has quit [Quit: leaving]
<sterni> seems like it's not possible to fix parsing of -9223372036854775808
<sterni> because negation / substraction is too contextual
<sterni> 12389 -3488 is a subtraction
<sterni> 0-100 is a subtraction
<sterni> and so on
<sterni> which all break my naive lexer fix
<sterni> I'm not convinced it's possible at all actually or not in a nice way at least
<sterni> welp, just one number
Dotz0cat has joined #nix-lang