malli

https://github.com/metosin/malli :malli:
borkdude 2021-03-08T10:03:56.243100Z

user=> (time (m/validate [:cat [:+ [:+ [:enum 0]]] [:enum 1]] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1]) )
"Elapsed time: 0.582137 msecs"
true
user=> (time (s/valid? (s/cat :zeroes (s/+ (s/+ #{0})) :one #{1}) [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1]))
"Elapsed time: 1265.3679 msecs"
(got the example from https://quanttype.net/posts/2021-03-06-clojure-spec-and-untrusted-input.html)

borkdude 2021-03-08T10:17:56.243600Z

Are there any examples of regexes that are slow in malli too?

miikka 2021-03-08T10:24:21.246900Z

Malli's regular expression matching algorithm is fundamentally different, so as far as i know, it does not have the exponential slow down problem. Probably you could still come up with some slow examples, but I don't have insight into what is slow and what is fast.

borkdude 2021-03-08T10:32:41.247100Z

Because it doesn't have backtracking, right?

miikka 2021-03-08T13:12:41.247600Z

It does use backtracking, but see the ns docstring for discussion: https://github.com/metosin/malli/blob/master/src/malli/impl/regex.cljc

borkdude 2021-03-08T14:48:22.248400Z

arundilipan 2021-03-08T15:23:09.249300Z

Sorry for the late response @borkdude @ikitommi, I had an health emergency this week and so I wasn’t able to do anything about it

arundilipan 2021-03-08T15:23:18.249700Z

I did follow up with the example and it did work

arundilipan 2021-03-08T15:23:52.250600Z

I have a follow-up question, though

arundilipan 2021-03-08T15:35:16.250800Z

I’m wondering if m/decode with the above schema is supposed to produce that result, and if so, I was wondering how to solve this so that I return [1.0 "A"] from decode?

ikitommi 2021-03-08T17:42:08.251500Z

@arundilipan works on my machine:

(ns sample.core
  (:require [malli.core :as m]
            [malli.transform :as mt]))

(def GreaterThanZero
  [:fn {:decode/string mt/-string->double}
   '#(> % 0)])

(def TestEnum
  [:enum "A" "B"])

(m/decode
  [:catn
   [:amount GreaterThanZero]
   [:layout TestEnum]]
  ["1.0" "A"]
  mt/string-transformer)
; => [1.0 "A"]

ikitommi 2021-03-08T17:45:31.254Z

if the result doesn’t match the schema after the transformation, the top-level schema returns the original. this is a feature of the current regex impl, doesn’t support partial transformation:

(m/decode
  [:catn
   [:amount GreaterThanZero]
   [:layout TestEnum]]
  ["1.0" "C"]
  mt/string-transformer)
; => ["1.0" "C"]

arundilipan 2021-03-08T17:46:23.254600Z

Oh that’s it, you’re right

arundilipan 2021-03-08T17:47:51.256200Z

In that case I guess the thing to do would be do use something like edn/read-string instead of decode? I’d like to make sure that the number is parsed regardless of the result of the rest of the :catn

ikitommi 2021-03-08T17:48:57.256700Z

or, you could use non-regex schema like :tuple:

(m/decode
  [:tuple GreaterThanZero TestEnum]
  ["1.0" "C"]
  mt/string-transformer)
; => [1.0 "C"]

ikitommi 2021-03-08T17:49:10.257Z

no :tuplen atm 😉

ikitommi 2021-03-08T17:50:16.258200Z

you could write issue about the partial decoding with regex?

ikitommi 2021-03-08T17:50:53.258900Z

(might be easy to fix)

arundilipan 2021-03-08T17:51:14.259200Z

Yea i’ll make an issue on the repo

arundilipan 2021-03-08T17:51:31.259600Z

Right now I’m trying to use the :catn variants because of the coercion into a map

arundilipan 2021-03-08T17:55:45.260Z

Done!