-
-
Save jspahrsummers/3114225 to your computer and use it in GitHub Desktop.
mutableStringWithString :: Id -> IO Id | |
mutableStringWithString str = | |
getClass "NSMutableString" <.> stringWithString str | |
arrayWithObjects :: [Id] -> IO Id | |
arrayWithObjects objs = do | |
getClass "NSArray" <.> arrayWithObjectsAndCount objs (length objs) |
Oh, of course. My bad.
K. Just a minute.
So, the question of variadic functions is probably a distraction here, since currying will do what you want. The only problem you will fall into is argument ordering. If the receiver parameter came last, for instance, then (>>=)
would be sufficient!
getClass :: String -> IO Id
arrayWithObjectsAndCount :: Num a => [Id] -> a -> Id -> IO Id
arrayWithObjects :: [Id] -> IO Id
arrayWithObjects xs =
getClass "NSArray" >>= arrayWithObjectsAndCount xs (length xs)
This approach also has further advantages: you should be able to compose message expressions in a point-free style using Kleisli composition: (>=>)
.
@jonsterling It's true that it would solve a lot of problems, but I think it'll be harder to understand for simpler cases, or imperative-style code in a do
, which right now can do infix message sends like:
mutableStringWithString str = do
nsstring <- getClass "NSString"
nsstring `stringWithString` str
@jonsterling Now, maybe declMethod
could define two functions – one with the receiver at the beginning, and one with it at the end. That might just exacerbate the confusion, though.
Yeah, you have a point with do-notation. Don't think generating two functions is the right solution. What we really want is a kind of long-distance flip combinator which makes a function take its first argument at the end. But I'm not sure that that is possible in the general case.
Alternatively, maybe we could do receiver at the end, along with a simple alias for return
:
concatNSStrings :: Id -> Id -> IO Id
concatNSStrings a b =
@ a >>= stringByAppendingString b
Hmmmmm. Maybe; not totally sure I dig it. I'm coming up with something hopefully and will be back in a few minutes.
OK. I sort of came up with such a combinator as I mentioned, but it's basically useless, since infix operators bind looser than function application.
(Additionally, your @
won't work, because symbols can only be infix operators.)
Furthermore, return x >>= blah
is usually a pretty clear sign that you shouldn't be using monadic binding in the first place! In fact, what you want for that instance is just flip ($)
. So, dig this:
(@.) = flip ($)
concatNSStrings :: Id -> Id -> IO Id
concatNSStrings a b =
a @. stringByAppendingString b
Right, but the @
was to solve the problem of a variadic application. Also, it could be written (@)
if need be (to get around the infix restriction).
Yeah, still not necessary if you're going to put the receiver at the end. So, you could do
concatNSStrings :: Id -> Id -> IO Id
concatNSStrings a b = (@) a stringByAppendingString b
if you want, but it doesn't really make a difference. (@)
is still just flip ($)
, with no bind in site. With currying, we have stopped caring about variadic nonsense.
I'm talking about this case:
f obj a b =
(@) obj >>= somethingWithTwoArguments a b
Unless I'm missing something, flip ($)
can't do that.
Ah, gotcha. You still won't be able to use (@)
as an alias for return
, since infix operators have to take two arguments.
And flip ($)
will work fine, because its function argument is partially applied; remember that function application binds tighter than infix operators. So, the following works:
(@.) = flip ($)
putFourStrings :: String -> String -> String -> String -> IO ()
putFourStrings a b c d = putStrLn a >> putStrLn b >> putStrLn c >> putStrLn d
"fourth" @. putFourStrings "first" "second" "third"
-- first
-- second
-- third
-- fourth
(In addition: the very fact that return x >>= f a b c
can do what you want it to indicates that x @. f a b c
can do the same. In fact, the two are provably equivalent).
Hmm, interesting. I'll make sure to add that. Thanks!
So, this works for the example you gave, and for any Id -> …
function, but it doesn't seem to work for IO Id -> …
:
mutableStringWithString :: Id -> IO Id
mutableStringWithString str = (getClass "NSMutableString") @. stringWithString str
Is there some way to make an <@.>
operator for lifting + applying + joining?
Yep! But you don't need to make a new operator. It's called (>>=)
. ;-)
mutableStringWithString str =
getClass "NSMutableString" >>= stringWithString str
That appears to drop str
into the self
position of stringWithString
, though.
Nope. Remember, we're putting the receiver last.
You're right. Sorry, I've been hopping back and forth between a few different mental models today.
;) no worries
@jonsterling No, it has to take a receiver and the argument, so
stringWithString :: Id -> Id -> IO Id
.Though perhaps I erred in my choice of
arrayWithObjectsAndCount
. Something that could just take a function with any number ofId
s would be good enough.