[{"data":1,"prerenderedAt":339},["ShallowReactive",2],{"project-30247325":3},{"id":4,"name":5,"line":6,"line_source":7,"title":8,"url":9,"domain":10,"maker":11,"posted_at":12,"year":13,"points":14,"comments":15,"rank_in_year":16,"shown_in_year":17,"top":18,"tier":19,"category":20,"subcategory":21,"format":22,"keywords":23,"reception":29,"sentiment":30,"stance_mix":31,"scored_comments":36,"aspects":37,"strip":42,"post_text":45,"what":46,"said":85,"maker_in_thread":151,"shape":159,"grid":163,"attempts":301,"same_week":302,"maker_shows":35,"maker_hidden":332,"reader_version":333,"card":334},"30247325","Koda","A typesafe functional toolkit for Python","title","Show HN: Koda, a typesafe functional toolkit for Python","https:\u002F\u002Fpypi.org\u002Fproject\u002Fkoda\u002F","pypi.org","keithasaurus",1644252369,2022,110,58,569,2570,23,"notable","languages","functional programming library","library",[24,25,26,27,28],"python","functional programming","maybe type","result type","typesafe","mixed",0.25,{"positive":32,"neutral":33,"mixed":34,"critical":35},9,7,0,3,19,{"execution":38,"design":39,"idea":40},{"positive":34,"critical":34},{"positive":34,"critical":34},{"positive":41,"critical":35},8,[35,34,34,34,43,34,34,34,34,35,34,35,34,34,34,34,34,44,44,43,35,43,43,34,34,34,35,34,34,34,34,34,34,43,34,43,35,35,34,43],5,1,null,{"problem":47,"audience":63,"pricing":45,"motivation":45,"time_to_build":45,"stack":72,"openness":83,"stage":84,"team_size":84},{"value":48,"source":49,"evidence":50},"Handling optional values and errors in Python without nested if checks","commenter",[51,55,59],{"id":52,"by":53,"text":54},"30249006","hackandtrip","Good luck checking for `None` equality and indent your code like 5 times... a sort of railway programming[0] avoids the awkward checks for values, making functions work with…",{"id":56,"by":57,"text":58},"30249427","btown","Say you're given a Python function in a large codebase that doesn't have documentation but does have type annotations, say, to indicate it returns Optional[str]. Does this tell…",{"id":60,"by":61,"text":62},"30250824","leethargo","I wanted to ask the same thing: Couldn't we just use Optional and None for this? So the point of using Koda is to communicate intent (functions that don't throw exceptions), and…",{"value":64,"source":65,"evidence":66},"Python developers who want functional, typed error handling","inferred",[67,71],{"id":68,"by":69,"text":70},"30248634","DandyDev","Because you'd like use the Python ecosystem, for example for writing ML code, but you'd also like to write typesafe code (or rather typechecked, using mypy)",{"id":56,"by":57,"text":58},[73],{"value":74,"source":75,"evidence":76},"Python","maker",[77,80],{"id":78,"by":11,"text":79},"30248028","So far I've been able to follow them. If you `raise` an exception during one of the functions that's used in a compose the traceback will mention the function that failed (I'm…",{"id":81,"by":11,"text":82},"30250756","> There is no procedural concepts like variable assignment allowed in a python lambda. Just a small note that the walrus operator gives you some wiggle room here: ```…","open_source","unknown",{"praise":86,"objections":98,"requests":117,"questions":125,"alternatives":134},[87],{"value":88,"source":49,"evidence":89},"Useful functional constructs for handling nullable and error values",[90,94],{"id":91,"by":92,"text":93},"30248231","fishmarmalade","Really nice project! I’ve been looking for something like this, and typically end up building a very minimal version of it for projects. Are you looking for help or contributors?…",{"id":95,"by":96,"text":97},"30249585","impoppy","Now this is an answer I was waiting for. Thank you for explaining the real benefits of sticking to koda style. I guess this would be obvious if I used statically typed languages…",[99,110],{"value":100,"source":49,"evidence":101},"Python already handles None with Optional and try\u002Fexcept",[102,105,109],{"id":103,"by":96,"text":104},"30248477","Why would you write Python like it’s Rust? I really fundamentally do not understand the purpose. Ain’t `is Null` checks and try except good enough?",{"id":106,"by":107,"text":108},"30248579","IshKebab","Yeah this sort of thing is necessary in statically typed languages like Rust and C++ but in Python (and e.g. Typescript) you can just use anonymous type unions like `str | None`.…",{"id":60,"by":61,"text":62},{"value":111,"source":49,"evidence":112},"Feels unpythonic and Rust-like",[113,114],{"id":103,"by":96,"text":104},{"id":115,"by":96,"text":116},"30248641","I let myself do a little bit of thinking and I guess this might be helpful when you are doing functional style pipes\u002Fchains but you can wrap the whole chain into a try except…",[118],{"value":119,"source":49,"evidence":120},"Higher-level collection functions like groupBy and countBy",[121],{"id":122,"by":123,"text":124},"30250990","zmmmmm","I want a similar toolkit that lifts over the Ruby\u002FGroovy\u002FKotlin style functions like countBy, groupBy, sortBy, collate, etc etc. Programming in Python is such a chore without…",[126],{"value":127,"source":49,"evidence":128},"Does composition preserve error messages and tracebacks",[129,133],{"id":130,"by":131,"text":132},"30247812","pizza","Nice. One question I have is does the compose operator preserve error messages, allow you to pinpoint which function raised an exception etc? That's the one issue I have w\u002F the…",{"id":78,"by":11,"text":79},[135,144],{"value":136,"source":49,"evidence":137},"dry-python returns",[138,141],{"id":139,"by":53,"text":140},"30248982","A similar \"framework\", very robust and used in production systems, is dry-python's one[0][1]. The approach taken is a bit different I think, since they rely heavily on `mypy`…",{"id":142,"by":11,"text":143},"30250283","dry-python has a lot of cool stuff. I encourage people to check it out. Koda has a slightly different approach in that it's meant to be a little simpler than returns, and to work…",{"value":145,"source":49,"evidence":146},"funct library",[147],{"id":148,"by":149,"text":150},"30253260","lauriat","There is https:\u002F\u002Fgithub.com\u002Flauriat\u002Ffunct which has some of those higher level functions.",{"comments":152,"answered":43,"key":153},6,[154,155,158],{"id":142,"text":143},{"id":156,"text":157},"30250007","Yeah, happy to have contributors. I'm not 100% certain on what the next features \u002F changes will be, so also happy to have input, requests, questions, etc.",{"id":78,"text":79},{"commenters":160,"max_depth":43,"maker_replies":152,"first_comment_mins":161,"lifespan_hours":162},32,30,51,[164,166,168,172,176,180,183,185,187,189,192,193,196,199,201,203,205,209,212,215,218,221,224,227,230,232,236,237,239,242,245,247,249,251,253,255,257,259,260,261,263,265,268,270,274,275,277,279,281,284,286,287,288,290,292,293,296,298],[139,34,35,165,53,34],"project\u002Fneutral\u002Fnone",[142,34,34,167,11,44],"project\u002Fneutral\u002Fdesign",[169,34,34,170,171,34],"30253935","other\u002Fneutral\u002Fnone","exdsq",[173,34,34,174,175,34],"30255459","commenter\u002Fneutral\u002Fnone","properdine",[177,34,34,178,179,34],"30277817","commenter\u002Fneutral\u002Fidea","chrischen",[181,34,34,174,182,34],"30256232","FreakLegion",[91,44,43,184,92,34],"project\u002Fpositive\u002Fnone",[156,44,34,186,11,44],"maker\u002Fneutral\u002Fnone",[122,188,34,170,123,34],2,[190,188,34,170,191,34],"30251765","wswope",[148,188,34,170,149,34],[194,188,34,170,195,34],"30254223","41b696ef1113",[197,188,34,170,198,34],"30254339","Daishiman",[130,35,35,200,131,34],"project\u002Fneutral\u002Fexecution",[78,35,34,202,11,44],"maker\u002Fneutral\u002Fexecution",[204,35,35,200,53,34],"30249045",[206,207,35,167,208,34],"30251452",4,"zestyping",[210,207,34,174,211,34],"30251505","RyEgswuCsn",[213,207,34,174,214,34],"30251559","cheriot",[216,207,34,174,217,34],"30251698","dragonwriter",[219,207,34,174,220,34],"30251701","CodeAndCuffs",[222,207,34,174,223,34],"30253066","bobbylarrybobby",[225,207,34,170,226,34],"30253125","growlfrench",[228,207,34,174,229,34],"30259517","r-zip",[103,43,44,231,96,34],"project\u002Fcritical\u002Fidea",[233,43,34,234,235,34],"30248508","commenter\u002Fcritical\u002Fidea","rmbyrro",[106,43,44,231,107,34],[52,43,43,238,53,34],"project\u002Fpositive\u002Fidea",[240,43,34,174,241,34],"30249103","ReleaseCandidat",[243,43,35,244,96,34],"30249358","project\u002Fneutral\u002Fidea",[246,43,43,238,53,34],"30249826",[248,43,34,234,107,34],"30256357",[250,43,43,238,217,34],"30249091",[252,43,34,174,96,34],"30249386",[254,43,34,174,217,34],"30253257",[256,43,34,174,57,34],"30249506",[258,43,34,174,217,34],"30249686",[68,43,43,238,69,34],[115,43,44,231,96,34],[262,43,34,174,217,34],"30249026",[264,43,34,174,96,34],"30249344",[266,43,34,174,267,34],"30250663","muxator",[269,43,34,174,217,34],"30251550",[271,43,34,272,273,34],"30249337","other\u002Fneutral\u002Fidea","deltaonefour",[81,43,34,186,11,44],[276,43,34,174,273,34],"30251192",[278,43,34,170,217,34],"30253825",[280,43,43,238,273,34],"30254115",[282,43,34,174,283,34],"30249390","ok_dad",[285,43,34,174,267,34],"30250700",[56,43,43,238,57,34],[95,43,43,238,96,34],[289,43,35,244,57,34],"30249878",[291,43,34,170,241,34],"30250141",[60,43,35,244,61,34],[294,43,34,295,11,44],"30251722","maker\u002Fneutral\u002Fidea",[297,43,34,186,11,44],"30249858",[299,43,43,238,300,34],"30253330","throwamon",[],[303,308,313,317,322,327],{"id":304,"name":305,"points":306,"category":307},"30244534","SHA-256 explained step-by-step visually",1241,"learning_science",{"id":309,"name":310,"points":311,"category":312},"30273940","Jless",344,"dev_tools",{"id":314,"name":315,"points":316,"category":307},"30193997","Reso",259,{"id":318,"name":319,"points":320,"category":321},"30267539","PgCat",233,"infrastructure",{"id":323,"name":324,"points":325,"category":326},"30257888","Three Magic Words",204,"games",{"id":328,"name":329,"points":330,"category":331},"30194440","Kapwing Smart Cut",171,"creative",false,"v2",{"id":335,"name":5,"line":6,"ai":332,"cat":20,"year":13,"points":14,"comments":15,"rec":29,"s":30,"top":18,"kw":336,"maker":11,"domain":10,"tier":19,"attempts":34,"strip":337,"url":9,"mix":338,"praise":88,"objection":100,"sub":21},30247325,[24,25,26,27,28],"3000500003030000011535500030000005053305",[32,33,34,35],1793991040606]