Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Locked thread
Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer
Whoops I guess I didn't provide enough information. When checkS is called, it is called like this
code:
check fname
  = do { input <- readFile fname
       ; putStr input
       ; case parse program fname input of
            Left err -> error (show err)
            Right x  -> return (checkS x [])
       }
So the list is initially empty. But now I think I've answered my own question. Any time a variable is encountered in a statement, add it to the list. Or something.

Adbot
ADBOT LOVES YOU

sarehu
Apr 20, 2007

(call/cc call/cc)
Well, they're saying "add it to the list," but that's speaking in functional programmer codetalk for "put it in the list you return/pass to some other function."

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer

sarehu posted:

Well, they're saying "add it to the list," but that's speaking in functional programmer codetalk for "put it in the list you return/pass to some other function."

Okay but I'm still totally lost.

here is what I have so far, which is wrong and broken
code:
checkS :: Stat -> [Ident] -> Bool
checkS c r = case c of -- this is obviously wrong,
                 (Skip _)       -> checkS (tail c) r --this statment does not contain any variables, but we still need to check the rest, so drop it from c and recurse
                 (Assign x e _) -> if (x `elem` r) then checkS (tail c) r else False --if the variable being assigned is in scope, continue, else return False
                 (Seq cs)       -> False
                 (If b _ s1 s2) -> False
                 (While b _ c)  -> False
                 (NewInt i c)   -> checkS c (i : r) --continue checking c, with i added to list of in scope variables
You can tell that it's wrong right away, because c is not a list. So the tail function obviously does not belong there. The recursion itself needs to be implemented in the Seq case, since that's the only place the code knows there's more than one statement.

man I love/hate this class. I spend hours and hours trying to understand that idea that the assignments are trying to communicate, because I simply don't understand what they're asking me. When I understand what they are ask, implementing those ideas becomes trivial. On the last assignment I spend an hour talking with the TA just to determine that that yes, translating the psuedo-code into the abstract language was what we were supposed to do. It's like pulling teeth to get these guys who consider all this stuff second nature to just explain what they want so I can start thinking about the problem.

edit: I am making progress, but I am still unsure how to handle the Seq case. Here is what I have now:
code:
checkS :: Stat -> [Ident] -> Bool
checkS c r = case c of -- this is obviously wrong,
                 (Skip _)       -> True --this statement contains no variables, so it cannot contain any undeclaired ones
                 (Assign x e _) -> (if (x `elem` r) then True else False) && checkE e r--if the variable being assigned is in scope, continue, else return False
                 (Seq cs)       -> checkS (head cs) r && checkS (Seq (tail cs)) r
                 (If b _ s1 s2) -> checkB b r && checkS s1 r && checkS s2 r
                 (While b _ c)  -> checkB b r && checkS c r
                 (NewInt i c)   -> checkS c (i : r) --continue checking c, with i added to list of in scope variables

Snak fucked around with this message at 06:29 on Nov 14, 2015

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Snak posted:

You can tell that it's wrong right away, because c is not a list. So the tail function obviously does not belong there. The recursion itself needs to be implemented in the Seq case, since that's the only place the code knows there's more than one statement.

What are the actual semantics of NewInt? It looks to me like you might be overthinking it a little bit.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

The creator of Elm just did a talk sort of about the benefit of immutability that I found pretty interesting:
https://www.youtube.com/watch?v=DfLvDFxcAIA

Snak
Oct 10, 2005

I myself will carry you to the Gates of Valhalla...
You will ride eternal,
shiny and chrome.
Grimey Drawer
Well I think I did get it all figured out last night. Thanks for the help. When I am stuck on a programming problem, I find that simply trying to explain the problem to other people often causes me to understand it better and make a breakthrough.

Jabor posted:

What are the actual semantics of NewInt? It looks to me like you might be overthinking it a little bit.

Well NewInt isn't a function in Haskell, it's a statement in the abstract language that we have defined. Here is the language:
code:
type  Ident = String
type  Label = Int

data AExp --Arithmetic Expression
  = Var Ident
  | IntLit Int
  | AOp String AExp AExp
  deriving Eq

data BExp --Boolean Expression
  = BUnOp String BExp --I forget what this is, I think it's just for handling "not <bool>" as being a boolean expression
  | BoolLit Bool --Boolean literal, ie True or False
  | BOp String BExp BExp --boolean operation
  | RelOp String AExp AExp -- boolean relation, >, <, ==, etc. 
  deriving Eq

data Stat --Statement
  = Assign Ident AExp Label
  | Skip Label
  | Seq [Stat]
  | If BExp Label Stat Stat
  | While BExp Label Stat
-- The new statement for defining variables:
  | NewInt Ident Stat
  deriving Eq
So the syntax of NewInt is "Newint Ident Stat", where Ident is the string identifier (the name) of the variable being declared and Stat is almost certainly of type Sequences of statements, which is what the scope of the variable will be.

Here is the code that ended up working. I am not 100% sure that is correct, because I was down to the wire and figured it out with 15 minutes left on the deadline and it passed the obvious tests.
code:
checkS :: Stat -> [Ident] -> Bool
checkS c r = case c of 
                 (Skip _)       -> True --this statement contains no variables, so it cannot contain any undeclaired ones
                 (Assign x e _) -> checkE (Var x) r && checkE e r--if the variable being assigned is in scope, continue, else return False
                 (Seq cs)       -> if length cs > 1 then (checkS (head cs) r && checkS (Seq (tail cs)) r) else checkS (head cs) r
                 (If b _ s1 s2) -> checkB b r && checkS s1 r && checkS s2 r
                 (While b _ c)  -> checkB b r && checkS c r
                 (NewInt i c)   -> checkS c (i : r) --continue checking c, with i added to list of in scope variables

checkE :: AExp -> [Ident] -> Bool
checkE e r = case e of
                  (Var x)        -> if (x `elem` r) then True else False --THIS IS THE FAILURE CASE I WAS LOOKING FOR. Took me long enough. 
                  (IntLit i)     -> True --not a variable, so not an undeclared variable
                  (AOp op e1 e2) -> checkE e1 r && checkE e2 r

checkB :: BExp -> [Ident] -> Bool
checkB b r = case b of
                  (BUnOp "not" b)    -> checkB b r
                  (BoolLit b)        -> True
                  (BOp "&" b1 b2)    -> checkB b1 r && checkB b2 r
                  (RelOp ">" e1 e2)  -> checkE e1 r && checkE e2 r
                  (RelOp "<=" e1 e2) -> checkE e1 r && checkE e2 r
Again, thanks for letting me post my bullshit here, it was actually really helpful.

Snak fucked around with this message at 19:40 on Nov 14, 2015

csammis
Aug 26, 2003

Mental Institution

Snak posted:

When I am stuck on a programming problem, I find that simply trying to explain the problem to other people often causes me to understand it better and make a breakthrough.

https://en.wikipedia.org/wiki/Rubber_duck_debugging :eng101:

LOOK I AM A TURTLE
May 22, 2003

"I'm actually a tortoise."
Grimey Drawer
A couple of tips, for future reference:

Snak posted:

code:
if (x `elem` r) then True else False

You can write this as just x `elem` r.

Snak posted:

code:
checkS c r = case c of 
    (Seq cs)       -> if length cs > 1 then (checkS (head cs) r && checkS (Seq (tail cs)) r) else checkS (head cs) r

If I'm not mistaken, this is a much simpler way to do the same thing:

code:
checkS c r = case c of 
    (Seq cs) -> all (\c -> checkS c r) cs
It also has the benefit that it won't fail if cs is somehow empty.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

Elm 0.16 was just released. There's a blog post about it: http://elm-lang.org/blog/compilers-as-assistants

The key feature is really the improved compiler error messages. I mean look at these, these are nice:




There's also some improved speed in the generated JS, and TCE, etc who cares

VikingofRock
Aug 24, 2008




drat, those are some nice error messages.

karms
Jan 22, 2006

by Nyc_Tattoo
Yam Slacker
Those errors are very un-functional. Maybe I should try out elm.

VikingofRock
Aug 24, 2008




Is there an up-to-date tutorial on regexes in Haskell? It seems like every tutorial is out-of-date, and the documentation on Hackage is fairly lacking.

tazjin
Jul 24, 2015


VikingofRock posted:

Is there an up-to-date tutorial on regexes in Haskell? It seems like every tutorial is out-of-date, and the documentation on Hackage is fairly lacking.

Usually when you're not sure whether a library on Hackage is still "current" you can check whether the same library is available on Stackage, which is a stable set of Haskell packages that requires them to be maintained.

From there we can find for example regex-compat, which seems to have a fairly simple interface. Consider the types of the functions as the documentation and view it a bit like a "type-puzzle" you are putting together. Example:

code:
-- Puzzle pieces:

-- We have a regular expression as a simple string
expression :: String

-- We have some text and want to find matches to the regular expression above 
stringToMatch :: String

-- The result we expect is a list of strings or something similar
expectedResult :: [String]
With the puzzle pieces we check out the documentation of the package and see if we find matching types:

code:
-- From Text.Regex in regex-compat:

-- A compiled regular expression.
data Regex

-- Now we know there is a type for compiled regular expressions, good!
-- How do we get there from our expression as a string?
-- We know we have a String, we want a Regex, and bingo:
mkRegex :: String -> Regex

-- Great, now we want something from our Regex and string to match (String) to some kind of [String], i.e. the result we want.
-- Back to the docs and we find:
matchRegex :: Regex -> String -> Maybe [String]

-- That looks like exactly what we're looking for! Now we just need to put the puzzle pieces together,
-- which is simple given the types above.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

A guy did a good talk at Strange Loop that I just watched where he gives a really high level description of what it's like to actually use Elm. I liked the talk:
https://www.youtube.com/watch?v=FV0DXNB94NE

Mr Shiny Pants
Nov 12, 2012

fart simpson posted:

A guy did a good talk at Strange Loop that I just watched where he gives a really high level description of what it's like to actually use Elm. I liked the talk:
https://www.youtube.com/watch?v=FV0DXNB94NE

Nice talk, it reminds of my first experience using F#: If it compiles it runs without errors.

What a great feeling. I might have to try Elm.

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



fart simpson posted:

A guy did a good talk at Strange Loop that I just watched where he gives a really high level description of what it's like to actually use Elm. I liked the talk:
https://www.youtube.com/watch?v=FV0DXNB94NE

The picture of O'Reilly's JavaScript next to java script: The Good Parts made me lol

Mr Shiny Pants
Nov 12, 2012

Munkeymon posted:

The picture of O'Reilly's JavaScript next to java script: The Good Parts made me lol

Me too, it is like 20% of the volume.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

I just took a trip down Elm memory lane. I've been messing around in Elm for over 2 and a half years now, and I just went back and updated one of my first projects that's still around on github with the bare minimum in updates so it will actually compile with the latest Elm version. It's kind of crazy how much Elm has grown in that time. Back then, everything was unorganized and nobody knew what they were doing or what coding style to use, so we were all 100% making it up as we went along.

I was probably one of the only people that's used the experimental Automaton library, which is based on Arrowized Functional Reactive Programming. I used it to implement a kind of lazy rendering system that would do a cheap, quick state diff and only re-render different pieces of the UI if their relevant state had changed, then it would cache the output for the next tick. This is what it looked like:
code:
module Rendertron where

import Signal
import String

import Model
import Interface
import SpecialEffects

import Automaton (..)
import Automaton

type Rendertron = Automaton Model.State Element
type HiddenState a = {input : a, render : a -> Element, output : Element}

rendertron : (Model.State -> a) -> (a -> Element) -> Model.State -> Rendertron
rendertron getter renderer state =
    let a = getter state
        state' = HiddenState a renderer <| renderer a
        step i s =  let a = getter i
                    in  if a == s.input
                        then (s, s.output)
                        else let o = renderer a
                             in  ({s| input <- a, output <- o}, o)
    in  hiddenState state' step

renderer : [Rendertron] -> Automaton Model.State [Element]
renderer rendertrons = Automaton.combine rendertrons

renderLines : Automaton Model.State [Element] -> Signal Model.State -> Signal Element
renderLines renderer state = flow down <~ run renderer [] state

renderGame : Int -> Automaton Model.State [Element] -> Signal Model.State -> Signal (Int, Int) -> Signal Element
renderGame seed renderer state dimensions =
    let instructions = constant Interface.instructions
        seed' = (\(w, h) -> container w h bottomLeft (plainText <| "random seed: " ++ show seed)) <~ dimensions
        elements = run renderer [spacer 0 0] state
        messages = (\elems (w, h) -> container w h (midTopAt (relative 0.5) (relative 0.7)) <| head elems) <~ elements ~ dimensions
        lines    = (\elems (w, h) -> container w h middle <| flow down (tail elems)) <~ elements ~ dimensions
        distorted = (\(w, h) state messages gameScreen -> layers [messages, gameScreen]) <~ dimensions ~ state ~ messages ~ lines
    in  layers <~ (Signal.combine [instructions, distorted, seed'])

-- Program specific:

lines : Model.State -> [Rendertron]
lines initialState =
    [ rendertron (\state -> state.messages)
        (\messages -> flow down <| map (plainText . .msg) messages)
        initialState
    , rendertron (\state -> ())
        (\_ -> flow right [Interface.chugButton, plainText " time acceleration: ", flow right Interface.timeAccelerationButtons])
        initialState
    , rendertron (\state -> (state.person.weight, state.person.orientation, state.person.gender, state.person.sex, state.person.alcoholism))
        (\(weight, orientation, gender, sex, alcoholism) -> flow right [ plainText "you are a "
                                                                       , plainText . String.left 5 . show <| weight, plainText "kg "
                                                                       , plainText . String.toLower . show <| orientation
                                                                       , plainText <| " " ++ showGender gender sex
                                                                       , plainText . showAlcoholism <| alcoholism
                                                                       ]
        )
        initialState
    , rendertron (\state -> .name (snd state.person.beers))
        (\name -> flow right [plainText "your current beer of choice is ", plainText . show <| name])
        initialState
    , rendertron (\state -> fst <| state.person.beers)
        (\beer -> flow right [plainText "of which you have ", width 35 <| plainText . show <| beer, plainText " ml left in the glass"])
        initialState
    , rendertron (\state -> state.person.alc)
        (\alc -> flow right [plainText "you got ", plainText . String.left 4 . show <| alc, plainText " grams of unabsorbed ethanol in ur belly"])
        initialState
    , rendertron (\state -> state.person.bac)
        (\bac -> flow right [plainText "ur bac is: ", plainText . String.left 6 . show <| bac])
        initialState
    , rendertron (\state -> (state.person.urine, state.person.wetSelf, state.person.urinating))
        (\(urine, wetSelf, urinating) -> plainText <| Interface.peeDisplay urine wetSelf ++ (if urinating then " (you are peeing)" else ""))
        initialState
    , rendertron (\state -> state.drinks)
        (\drinks -> flow right [plainText "you've had ", plainText . String.left 4 . show <| drinks, plainText " beers"])
        initialState
    ,  rendertron (\state -> Interface.timeDisplay state.elapsed)
        (\elapsed -> flow right [plainText "u been at the bar for: ", plainText elapsed])
        initialState
    ,  rendertron (\state -> ())
        (\_ -> flow right [Interface.sipButton, Interface.gulpButton, Interface.urinateButton])
        initialState
    ,  rendertron (\state -> ())
        (\_ -> flow right [Interface.orderButton, Interface.orderButton2])
        initialState
    , rendertron (\state -> (state.person.conscious, state.person.alive))
        (\(conscious, alive) -> if | not alive -> centered . Text.height 30 . bold . toText <| "you are dead. rip"
                                   | not conscious -> centered . Text.height 30 . bold . toText <| "you've passed out"
                                   | otherwise -> spacer 0 0
        )
        initialState
    ]

showGender : Model.Gender -> Model.Sex -> String
showGender gender sex =
    case sex of
        Model.Male   -> if gender == Model.Cis then "cisman" else "transwoman"
        Model.Female -> if gender == Model.Cis then "ciswoman" else "transman"


showAlcoholism : Float -> String
showAlcoholism a = if | a < 0.25  -> " who never drinks"
                      | a < 1     -> " social drinker"
                      | a < 1.5   -> " heavy drinker"
                      | a < 2     -> " functioning alcoholic"
                      | otherwise -> " alcoholic"
But now everyone uses a totally different UI library called elm-html which has lazy rendering built in, and everything's much more standardized around a common app architecture. We have a style guide, a gofmt style utility called elm-format, and it's just very different. Here's a simple website I've started working on recently:
code:
module Main where

import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import Graphics.Element exposing (..)
import Color

import StartApp.Simple as StartApp


main =
  StartApp.start { model = model, view = view, update = update }



port title : String
port title =
  "Title"


model = 
  False


update action model =
  case action of
    _ -> not model


view address model =
  div 
    [ style 
      [ ("fontFamily", "\"Raleway\", sans-serif") 
      , ("color", "black")
      , ("position", "relative")
      ] 
    ] 
    [ hamburger address model
    , fullscreenMenu address model
    , logo
    , body
    , footer
    , node "link"
      [ rel "stylesheet"
      , href "https://fonts.googleapis.com/css?family=Raleway:400,700,900,800"
      , type' "text/css"
      ]
      []
    ]


logo =
  div 
    [ style 
      [ ("cursor", "pointer") 
      , ("fontSize", "20px")
      , ("fontWeight", "800")
      , ("lineHeight", "80px")
      , ("width", "400px")
      , ("margin", "0px auto")
      ] 
    ] 
    [ text "GIGI"
    , spacer 150 1 |> color Color.lightGrey |> fromElement
    , node "link" 
      [ rel "stylesheet"
      , href "https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css"
      ]
      []
    ]
    

body =
  div 
    [ style 
      [ ("fontSize", "13px")
      , ("color", "#8D8D8D")
      , ("lineHeight", "22px")
      , ("letterSpacing", "1px")
      , ("width", "400px")
      , ("margin", "50px auto")
      ]
    ] 
    [ h1 
      [ style 
        [ ("fontSize", "43px")
        , ("fontWeight", "900")
        , ("lineHeight", "70px")
        , ("color", "black")
        , ("letterSpacing", "0px")
        ]
      ] 
      [ text "PROJECTS" ]
    , text "Please check my portfolio."
    , pic Color.grey
    , pic Color.lightGrey
    , pic Color.grey
    ]


hamburger address model =
  node
    "i"
    [ class <| if model then "fa fa-close" else "fa fa-bars"
    , style 
      [ ("backgroundColor", "black") 
      , ("position", "fixed")
      , ("right", "5%")
      , ("top", "30px")
      , ("padding", "20px")
      , ("color", "white")
      , ("fontSize", "18px")
      , ("cursor", "pointer")
      , ("zIndex", "9999")
      ]
    , onClick address ()
    ]
    []
    

fullscreenMenu address model =
  if model then
    div
      [ style
        [ ("position", "fixed")
        , ("height", "100%")
        , ("width", "100%")
        , ("background", "rgba(0, 0, 0, 0.95)")
        , ("zIndex", "9998")
        ]
      ]
      [ text "welp," ]
  else
    div [] []


footer =
  div
    [ style 
      [ ("height", "300px")
      , ("marginTop", "150px")
      , ("background", "#F1F1F1")
      , ("color", "#686868")
      , ("letterSpacing", "1px")
      , ("fontSize", "12px")
      , ("textAlign", "center")
      ]
    ]
    [ divSpacer 150
    , text "© Copyright 2015 deadfoxygrandpa.xyz. All Rights Reserved." 
    ]


pic c =
  p [] [ spacer 360 305 |> color c |> fromElement ]
  
  
divSpacer h =
  div
    [ style
      [ ("height", toString h ++ "px")
      , ("width", "100%")
      ]
    ]
    []
There was no real point to this post, it was just something that I thought was kind of fun to look back on.

Jerry Bindle
May 16, 2003
Does anyone know of a racket function/macro that does something like these clojure operators?

http://clojuredocs.org/clojure.core/-%3E
http://clojuredocs.org/clojure.core/-%3E%3E

The clojure docs use the word "thread" to describe the behavior, which is a good word to use except for the fact that there is another more common thing that uses that same word so its hard to search for.

Backing up a sec -- what I want to do is use (make-immutable-hash) as a data structure to represent the memory in an mcu emulator. I'm using the immutable hash-table because I want to force it to be ~functional~. The code that actually implements the emulator doesn't need this kind of operator, but it would be helpful in setting up data for testing the implementation.

Here's what I can do with what i know now




Here's what I think might save me some typing keystrokes




I suspect that the -> operators only exist in Clojure to aide the usage of chaining method calls from java APIs, so maybe -> is unracketish. Any advice?


-----

edit: I've tried doing a typed/required decl for hash-set* but I couldn't figure it out. hash-set* does what I want to do but I don't know how to write the contract for it.

-----

Update, I think I can write a macro to expand it to this,

Lisp code:
(hash-set
 (hash-set
  (hash-set
   (hash-set
    (hash-set h 'k1 1)
    'k2 2)
   'k3 3)
  'k4 4)
 'k5 5)
-----

Solved it with a plain old function. Posting it here for anyone who is interested, including myself 4 weeks from now when i forget what i was thinking.

Lisp code:
(: set-up-ram (-> Memory-Section (Listof Memory-Key) (Listof Memory-Value)
                  Memory-Section))
(define (set-up-ram ms ks vs)
  (if (pair? ks)
      (set-up-ram (hash-set ms (car ks) (car vs))
                  (cdr ks)
                  (cdr vs))
      ms))

Jerry Bindle fucked around with this message at 21:10 on Dec 17, 2015

Jerry Bindle
May 16, 2003

:eyepop: Your Elm posts always make me want to do more with Elm. I've done a little, but not enough.

VikingofRock
Aug 24, 2008




Barnyard Protein posted:

:eyepop: Your Elm posts always make me want to do more with Elm. I've done a little, but not enough.

Same here. I've never really had any desire to do web stuff, but fart simpson's elm posts make it look so slick.

fart simpson
Jul 2, 2005

DEATH TO AMERICA
:xickos:

For fun, that Automaton lazy renderer ended up being used for this: http://beer.deadfoxygrandpa.xyz. This was before Elm had the elm-html package, so all the graphics were done in a kind of weird but cool abstraction layer that didn't give you any access at all to normal HTML or CSS stuff.

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy

VikingofRock posted:

Same here. I've never really had any desire to do web stuff, but fart simpson's elm posts make it look so slick.

As long as you stick to Elm's primary use case (UI FRP), then most of your code will look slick. We used elm-svg to make cool data visualizations with animations and all the jazz that people would normally use D3.js for, but without the lovely selector-based programming that the D3 API requires.

Votlook
Aug 20, 2005

Barnyard Protein posted:

Does anyone know of a racket function/macro that does something like these clojure operators?

http://clojuredocs.org/clojure.core/-%3E
http://clojuredocs.org/clojure.core/-%3E%3E

[/code]

There is no built in macro that does this in Racket, but I know at least one library that provides it, Rackjure
http://www.greghendershott.com/rackjure/index.html#%28part._.Threading_macros%29

KaneTW
Dec 2, 2011

GHC 8.0 release candidate is around the corner, including cool stuff like -XTypeInType (blog post about it), Strict Haskell, Duplicate Record Fields (allows you to have record field names where the ambiguity is resolved during typechecking) and a whole lot of other stuff.

Jerry Bindle
May 16, 2003

Votlook posted:

There is no built in macro that does this in Racket, but I know at least one library that provides it, Rackjure
http://www.greghendershott.com/rackjure/index.html#%28part._.Threading_macros%29

Awesome, thank you!

Maluco Marinero
Jan 18, 2001

Damn that's a
fine elephant.
So I'm going through a phase of being ridiculously sold on Elm and wanting to try something non trivial in it. Seriously watch Evan's Lets be Mainstream talk, it's amazing to see a young language in the front end with responsible management, ensuring you can actually rely on packages, coding style, etc etc.

The foundation of the elm architecture is great too. I had one question though that maybe fart simpson could help me with. With the StartApp package it has a way to send in inputs and map them to actions for the model. Do components have any way to request Signals themselves, as I can see cases where you'd have say a Draggable component, and that'd like to listen to the Mouse.position signal once you start dragging, or a timer listening to (Time.every Time.millisecond).

All that said though, the animation example nearly gets there with Effects.tick. You're element is always going to know whether it needs to be reading from a signal, with a Draggable it would have a state of Dragging so it knows to trigger an effect at that point, so I guess all I'd be looking for is a way to make a Signal be polled by a Task that you can map into an effect. Does this seem reasonable? If it's at all possible to collect from a Signal with a task then you can keep the Static Signals, yet only be turning them into actions when actually required, keeping the possible complications down of polling say the Mouse position continuously.

I guess what I'm looking for is just something that can do (Signal a -> Task Never a) and then if be golden. Elm could do with a Hoogle-like.

Sinestro
Oct 31, 2010

The perfect day needs the perfect set of wheels.
I'm curious about people's experiences using Elm to develop a traditional website versus a 'web app', in terms of stuff like URLs and just general advice.

Rudest Buddhist
May 26, 2005

You only lose what you cling to, bitch.
Fun Shoe
I tried using elm on a little scheduling pet project and could not find a decent way to get around basic routing. I think it really shines on fancy single page web apps.

Maluco Marinero
Jan 18, 2001

Damn that's a
fine elephant.
By the looks of it it's just missing a decent package. Routing in web apps is pretty straightforward if you know how to go about it, with something that can map paths to a Route Type with parameters.

You'd need to write Native bindings to do it properly in Elm though, so you can bind to the various page change events.

KaneTW
Dec 2, 2011

Visible type application might make it into GHC 8.0, allowing you to write things like
code:
:t length
length :: Foldable t => t a -> Int
:t length @[]
length :: [a] -> Int
or a more useful example,
code:
:t read
read :: Read a => String -> a
:t read @Int
read :: String -> Int
This is especially nice whenever you used to need a proxy type or similar to disambiguate typevars.

Horse Clocks
Dec 14, 2004


Barnyard Protein posted:

Does anyone know of a racket function/macro that does something like these clojure operators?

http://clojuredocs.org/clojure.core/-%3E
http://clojuredocs.org/clojure.core/-%3E%3E

The clojure docs use the word "thread" to describe the behavior, which is a good word to use except for the fact that there is another more common thing that uses that same word so its hard to search for.

Out of boredom I took a stab at implementing thread-first as a function. I got close, but don't know much about rackets quoting/unquoting, so the syntax is dumb.

I also don't have racket installed, so I'm using try-racket.org and I want to stab my hands to death.

Lisp code:
(define (thread-first value functions)
  (if (eq? (length functions) 0)
    value
    (let* ([head (car functions)]
           [tail (cdr functions)]
           [func (car head)]
           [args (cdr head)])
      (thread-first 
        (apply func value args) tail))))

(thread-first 0 (list (list + 1)
                      (list * 2)
                      (list / 4)))
1/2

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



I'm loving around in Elm and trying to do the exercises in http://elm-lang.org/examples/binary-tree

For #2 I tried to do
code:
flatten : Tree a -> List a
flatten tree = 
    case tree of
      Empty -> []
      Node value left right -> 
          flatten left :: value :: flatten right
But I'm getting an infinite type error for left in the second case branch (I guess you'd call it? as in Node value left right ->) and have no idea how to apply the advice in https://github.com/elm-lang/elm-compiler/blob/0.16.0/hints/infinite-type.md because I'm an f-lang noob. What did I do wrong?

sarehu
Apr 20, 2007

(call/cc call/cc)
I don't know Elm but I'll bet you a zillion bucks it's that the type of "::" is a -> List a -> List a and also by the way it's probably right-associative.

flatten left returns a List a, and (value :: flatten right) evaluates to a List a.

You need to append the lists using an append function, you're trying to cons them together.

Edit: Edited to pretend more convincingly that I didn't check the Elm docs before writing parts of this reply.

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



Yep, that's it. I thought I was being all clever there by avoiding implicitly creating a bunch of basically-useless single-element lists.

VikingofRock
Aug 24, 2008




Munkeymon posted:

Yep, that's it. I thought I was being all clever there by avoiding implicitly creating a bunch of basically-useless single-element lists.

I think that would get compiled away anyways, but if not I think this would work:

code:
flatten : Tree a -> List a
flatten tree = 
    case tree of
      Empty -> []
      Node value left right -> 
          flatten left ++ (value :: flatten right)
edit: You might not even need the parens, depending on operator precedence.

VikingofRock fucked around with this message at 23:52 on Dec 30, 2015

Munkeymon
Aug 14, 2003

Motherfucker's got an
armor-piercing crowbar! Rigoddamndicu𝜆ous.



VikingofRock posted:

I think that would get compiled away anyways, but if not I think this would work:

code:
flatten : Tree a -> List a
flatten tree = 
    case tree of
      Empty -> []
      Node value left right -> 
          flatten left ++ (value :: flatten right)
edit: You might not even need the parens, depending on operator precedence.

Yep, that works without the parens.

Meantime, my dumbass attempts at writing fold are crashing their compiler service :(

Sinestro
Oct 31, 2010

The perfect day needs the perfect set of wheels.
I was pretty sold on Elm, until I started to try and actually write stuff. I really hate the stupid "no typeclasses, if you really need it just pass an explicit record around!" poo poo. It's a functional language, it'll mostly be used by people that understand it, and if you don't dive right into monad bullshit, it's a pretty simple concept. I don't think that you should be programming if you can't understand the concept of a constraint.

HappyHippo
Nov 19, 2003
Do you have an Air Miles Card?

Sinestro posted:

I was pretty sold on Elm, until I started to try and actually write stuff. I really hate the stupid "no typeclasses, if you really need it just pass an explicit record around!" poo poo. It's a functional language, it'll mostly be used by people that understand it, and if you don't dive right into monad bullshit, it's a pretty simple concept. I don't think that you should be programming if you can't understand the concept of a constraint.

Agreed. I also think the whole "no monads!!!" thing itself is pretty silly. They've reimplemented Applicative like half a dozen times in the core libraries, its ridiculous that there's so many versions of map/map2/map3/... when they could just define them once and be done with it. Is this because typeclasses are difficult to implement, or is this from the "for your own good" school of language design? Or are they just concerned that people will be turned off the language if it has monads in it?

Adbot
ADBOT LOVES YOU

sarehu
Apr 20, 2007

(call/cc call/cc)
If you're making an interesting programming language these days it's become a requirement to scare off the functional programming morons. Avoiding type classes helps them establish their market position.

  • Locked thread